Ersetzen und Trennen mit regulären Ausdrücken
Neben dem Operator -match gibt es zwei weitere Operatoren, die mit regulären Ausdrücken umgehen können, nämlich -split und -replace.
split
-split ist hilfreich, wenn ein Text an einem Muster aufgetrennt werden soll. Standardmäßig trennt der Split-Operator bei Leerzeichen. Der zu verarbeitende Text steht hinter -split:
-split 'Heute ist ein guter Tag zum Skripten'
>Heute
>ist
>ein
>guter
>Tag
>zum
>Skripten
Interessanterweise ändert sich das Verhalten, wenn man das Trennzeichen angeben möchte, denn dann steht der String vor -split, und die Parameter stehen dahinter. Die Syntax lautet also
<String> -split <Trennzeichen>
Mit -split ist es z.B. möglich, die Pfad-Variable $env:Path in Einzelpfade aufzutrennen.
$env:Path -split ';'
Das geht alternativ auch mit der String-Methode Split(). Im Gegensatz zur Methode kann der Operator allerdings auch reguläre Ausdrücke als Trennzeichen verwenden. Wenn Sie den Pfad also anstatt am Semikolon (warum auch immer) lieber am Laufwerksbuchstaben trennen möchten, versuchen Sie doch einfach mit
$env:path -split 'c:\\'
Achten Sie darauf, dass wir es hier mit einem regulären Ausdruck zu tun haben, und "\" eine besondere Bedeutung hat. Er muss durch einen zweiten "\" Escaped werden. Das kann zu einiger Verwirrung führen. Vergessen Sie den Backslash, bekommen Sie nämlich eine Fehlermeldung:
$env:path -split '[c-z]:\'
> "[c-z]:\" wird analysiert - Unzulässiger \ am Ende des Musters.
> In Zeile:1 Zeichen:1
> •$env:path -split '[c-z]:\'
> + ~~~~~~~~~~~~~~~~~~~~~~~~~~
> •CategoryInfo : OperationStopped: (:) [], ArgumentException
> •FullyQualifiedErrorId : System.ArgumentException
Sie können -split aber auch dazu zwingen, anstatt eines regulären Ausdrucks einen einfachen String-Vergleich zu machen. Der vergleicht allerdings wirklich nur den angegebenen String und unterstützt keine Wildcards wie [c-z]!
$env:path -split '[c-z]:\',0,'Simplematch' # Kein Ergebnis!
$env:path -split 'c:\',0,'Simplematch
Die Ziffer Null zwischen dem Muster und der Option 'Simplematch' ist übrigens ein weiterer Parameter, der hier zwingend angegeben werden muss. Gibt man eine positive Zahl größer Null ein, bestimmt die-ser Parameter, wie viele Ausgabewerte erzeugt werden sollen. Der letzte Wert enthält dann den Rest des Strings.
$env:path -split '[c-z]:\\',3
> Windows\system32;
> Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files\SysinternalsSuite;C:\Program Files\Git\cmd; […]
-Split unterstützt weiterhin noch die Optionen 'Regex', 'IgnoreCase', 'CultureInvariant', 'IgnorePattern-WhiteSpace', 'Multiline', 'Singleline' und 'ExplicitCapture'. Eine genaue Beschreibung dieser Optionen finden Sie in der Hilfe unter get-help about_split.
replace
Der -replace-Operator arbeitet ähnlich wie der Split-Operator, ersetzt allerdings einen gefundenen String durch einen anderen. Wenn Sie in der Path-Variablen das Komma durch ein Semikolon ersetzen wollen, ist -replace also eine gute Option.
$env:path -replace ';',','
Sie können auch alle im Pfad vorkommenden Laufwerksbuchstaben durch einen anderen ersetzen lassen, z.B. durch D:
$env:path -replace '[C-Z]:\\','D:\'
Dieses Beispiel macht nur wenig Sinn, aber es zeigt, dass auch -replace mit regulären Ausdrücken arbeitet. Achten Sie daher unbedingt darauf, dass Sie \\ eingeben müssen, wenn Sie einen \ ersetzen wollen, da der Replace-Operator keinen Simplematch kennt.
Ein besonders hilfreiches Feature von -replace ist die Möglichkeit, Gruppen im zu ersetzenden Text zu referenzieren. Stellen Sie sich z.B. vor, Sie haben folgenden Text in Form eines Here-Strings vorliegen und möchten ihn in eine Hash-Table umwandeln:
$Log = @'
AGENT - Windows Update-Agent
AU - Die automatische Aktualisierung führt diesen Vorgang durch. AUCLNT - Interaktion von AU mit dem angemeldeten Benutzer
CDM - Geräte-Manager
CMPRESS – Komprimierungsagent COMAPI - Windows Update-API '@
Es handelt sich hier übrigens um die Namen der Komponenten, die im Windows Update Log auftreten können. Für die Ersetzung müssen Sie zuerst den Text Links und Rechts vom Bindestrich als Gruppe extrahieren. Dafür reicht folgender Ausdruck:
'\s*(\w*)\s*-\s*(.*)'
Die erste Klammer extrahiert das erste Wort auf der linken Seite. Hinter dem Wort folgende Leerzeichen werden nicht in der Gruppe erfasst. Danach folgt der Bindestrich sowie folgende Leerzeichen, die eben-falls nicht erfasst werden. Nach dem zweiten Leerzeichen auftretende Zeichen werden in die zweite Gruppe aufgenommen. Im Ersetzungsmuster können wir auf die Gruppen jetzt mit dem Dollar-Zeichen sowie dem Index der Gruppe direkt auf die gefundenen Gruppen referenzieren.
$log.split("'n") | ForEach-Object { $_ -replace '(\w*)\s-\s*(.*)','$1 = "$2"' }
> AGENT = "Windows Update-Agent"
> AU = "Die automatische Aktualisierung f³hrt diesen Vorgang durch."
> AUCLNT = "Interaktion von AU mit dem angemeldeten Benutzer"
> CDM = "Geräte-Manager"
> CMPRESS = "Komprimierungsagent" COMAPI = "Windows Update-API"
Da der Text in einem Here-String vorliegt, wird er nicht zeilenweise in die Pipeline weitergegeben. Daher muss er erst mit der String-Methode Split an den Zeilenumbrüchen "`n" aufgetrennt werden. Der Operator Replace erledigt den Rest, indem er als Ersetzung für den kompletten Ausdruck die erste Gruppe ausgibt, gefolgt von einem Leerzeichen, einem Gleichheitszeichen, noch einem Leerzeichen und der zweiten Gruppe, die in Anführungszeichen eingeschlossen ist.
-split 'Heute ist ein guter Tag zum Skripten'
>Heute
>ist
>ein
>guter
>Tag
>zum
>Skripten
Man kann reguläre Ausdrücke auch in Cmdlets wie Rename-Item zum mehrfachen umbenennen verwenden.