1 Der System.Text.RegularExpressions-Namespace
1.1 Einleitung
     Beispiel 1: Durchsuchen eines Strings auf alle Übereinstimmungen
1.2 Regex-Klasse
     Beispiel 1a: statische Methoden der Klasse Regex
     Beispiel 1b: Instanzbasierte Methoden der Klasse Regex
1.2.1 Mit der Regex-Klasse instanzbasiert und instanzfrei arbeiten
        Beispiel 1: Erstellen einer Instanz der Regex-Klasse ohne Optionen
        Beispiel 2: Erstellen einer Instanz der Regex-Klasse mit Optionen
        Beispiel 3a: Einen Satz in Wörter splitten mit der statischen Split-Methode
        Beispiel 3b: Einen Satz in Wörter splitten mit der Split-Methode (Instanz)
       Beispiel 3c: Einen Satz in Wörter splitten mit dem Split-Operator
1.2.2 Regex-Methoden
        Beispiel 1a: Prüfen, ob ein String eine formal gültige IP-Adresse darstellt
        Beispiel 1b: Prüfen, ob ein String eine formal gültige email-Adresse darstellt
        Beispiel 3: Durchsuchen eines Strings auf alle Übereinstimmungen (Matches-Methode)        
1.3 Regex-Options
 

1 Der System.Text.RegularExpressions-Namespace

MSDN: System.Text.RegularExpressions-Namespace

 

1.1 Einleitung

Die Klassen dieses Namespaces bieten viele Möglichkeiten skalare Strings zu analysieren. Im Gegensatz zu den Vergleichsoperatoren aus Kapitel 2 können sie aber nicht auf ganze Arrays angewendet werden, auf einzelne Arrayelemente natürlich schon.

 

Beispiel 1: Durchsuchen eines Strings auf alle Übereinstimmungen (RegexMethoden Match/ NextMatch)

Set-StrictMode -Version "2.0"
Clear-Host

$String = "sz KarlA Kbrl KcrlNapf 3KdrlZz"
$Pattern = "K[a-d]rl" #True bei Karl, Kbrl, Kcrl, Kdrl

$Regex = [Regex]$Pattern
#$Regex = New-Object System.Text.RegularExpressions.Regex $Pattern  #identisch
#$Regex = [System.Text.RegularExpressions.Regex] $Pattern #identisch
#$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,"IgnoreCase") #Plus RegexOption: Ignorecase

$Match = $Regex.Match($String) #Instanz der Klasse "System.Text.RegularExpressions.Match"
"Index: {0}  Value: {1}" -f $Match.Index,$Match.Value

While($Match.success -match $True){
  $Match = $Match.Nextmatch()
  If($Match.Success -Match $True){
   "Index: {0}  Value: {1}" -f $Match.Index,$Match.Value
   } #If
 } #While
#Ausgabe

Index: 3  Value: Karl
Index: 9  Value: Kbrl
Index: 14  Value: Kcrl
Index: 24  Value: Kdrl

In diesem Beispiel wird eine Instanz der Klasse [Regex] erstellt

RegexOptions: siehe Kapitel 3.3

 

2 Regex-Klasse

MSDN: Regex-Klasse

Wie man in dem Link sehen kann, besitzt die Regex-Klasse für viele Aufgaben, sowohl statische (zu erkennen am roten "S"), wie nicht statische gleichlautende Methoden. Beispiele sind die Methoden "Match", "Matches" oder "Replace". 

Mit dem cmdlet Get-Member und dem Positionsparameter bekommt man natürlich ebenso die statischen, wie nichtstatischen Methoden:

 

Beispiel 1a: statische Methoden der Klasse Regex

[Regex] | Get-Member -Static
#Ausgabe gekürzt
  TypeName: System.Text.RegularExpressions.Regex

Name              MemberType Definition    
----              ---------- ----------  

IsMatch           Method     static bool IsMatch(string input, string pattern),...
Match             Method     static System.Text.RegularExpressions.Match Match(string input, string pattern), .
Matches           Method     static System.Text.RegularExpressions. ...
ReferenceEquals   Method     static bool ReferenceEquals(System.Object objA, System.Object objB)    
Replace           Method     static string Replace(string input, string pattern, string replacement), ...
Split             Method     static string[] Split(string input, string pattern),  
 


Beispiel 1b: Instanzbasierte Methoden der Klasse Regex

[Regex] | Get-Member -MemberType Method
#Ausgabe gekürzt
   TypeName: System.String

Name             MemberType Definition
----             ---------- ----------
Clone            Method     System.Object Clone()
CompareTo        Method     int CompareTo(System.Object value), int CompareTo(string strB)
...
ToUpperInvariant Method     string ToUpperInvariant()
Trim             Method     string Trim(Params char[] trimChars), string Trim()
TrimEnd          Method     string TrimEnd(Params char[] trimChars)
TrimStart        Method     string TrimStart(Params char[] trimChars)

Man sieht, dass diese Liste der instanzbasierten (=nicht-statischen) Methoden doch länger ist, als die Liste der statischen Methoden. 
Es gibt Methoden, die sowohl in der statischen, wie auch in der nicht statischen Liste vorkommen, etwa Match, Replace, Split

Die unterschiedliche Anwendung statischer und nicht-statischer Methoden zeige ich im folgenden Kapitel in Beispielen.
 

1.2.1 Mit der Regex-Klasse instanzbasiert und instanzfrei arbeiten

Möchte man die nicht-statischen Methoden nutzen, so braucht man zuerst eine Instanz der Klasse Regex (Beispiele 1 und 2)
In Beispiel 3 vergleiche ich die beiden Split-Methoden (statisch und nichtstatisch) und den Split-Operator. 


Beispiel 1: Erstellen einer Instanz der Regex-Klasse ohne Optionen

Set-StrictMode -Version "2.0"
Clear-Host

$String = "sz karlA Kbrl KcrlNapf 3KdrlZz"
$Pattern = "K[a-d]rl" #True für Karl, Kbrl, Kcrl, Kdrl

$Regex = [Regex]$Pattern
#$Regex = New-Object System.Text.RegularExpressions.Regex $Pattern  #identisch
#$Regex = [System.Text.RegularExpressions.Regex] $Pattern #identisch

$Match = $Regex.Match($String)
"Index: {0}  Value: {1}" -f $Match.Index,$Match.Value
#Ausgabe

Index: 9  Value: Kbrl

Ohne die Option "IgnoreCase" (siehe nächstes Beispiel) werden nur Treffer zurückgegeben, die casesensitiv mit dem Suchkriterium übereinstimmen.


Beispiel 2: Erstellen einer Instanz der Regex-Klasse mit Optionen

Set-StrictMode -Version "2.0"
Clear-Host

$String = "sz karlA Kbrl KcrlNapf 3KdrlZz"
$Pattern = "K[a-d]rl" #True bei Karl, Kbrl, Kcrl, Kdrl  (ohne RegExOptions)

$RegOps = [System.Text.RegularExpressions.RegexOptions]("IgnoreCase","Multiline")
$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,$RegOps)
#$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,"IgnoreCase")

$Match=$Regex.Match($String)
"Index: {0}  Value: {1}" -f $Match.Index,$Match.Value
#Ausgabe

Index: 3  Value: karl

Mit Option "IgnoreCase" werden auch Treffer zurückgegeben, die nicht casesensitiv mit dem Suchkriterium übereinstimmen.

 
Beispiel 3a: Einen Satz in Wörter splitten mit der statischen Split-Methode

$String = 'Mein,guter?Freund*Karl Napf'
$Pattern = "\W"
[Regex]::Split($String,$Pattern)
#Ausgabe

Mein
guter
Freund
Karl
Napf

"\W" entspricht einem beliebigen "Nicht-Wortzeichen", also jedem Zeichen, das kein Buchstabe und keine Zahl ist.

Hier wird die statische Form der Split-Methode benutzt. Für statische Methoden muss man die Schreibweise "[Klasse]::Methode(Parameter)" anwenden.  

Technet: about_operators -> ::-Operator für statische Elemente 

 
Beispiel 3b: Einen Satz in Wörter splitten mit der Split-Methode (Instanz)

Set-StrictMode -Version "2.0"
Clear-Host

$String = 'Mein,guter?Freund*Karl Napf'
$Pattern = "\W"

$Regex = [Regex]$Pattern
#gleichbedeutend mit
#$Regex = [System.Text.RegularExpressions.Regex] $Pattern
#$Regex = New-Object System.Text.RegularExpressions.Regex $Pattern

$Regex.Split($String)
#Ausgabe wie in Beispiel 3a

Seht euch am besten die Split-Methode unter MSDN: Regex-Klasse -> Methoden, mit den verschiedenen Möglichkeiten an. 


Beispiel 3c: Einen Satz in Wörter splitten mit dem Split-Operator

Set-StrictMode -Version "2.0"
Clear-Host

$String = 'Mein,guter?Freund*Karl Napf'
$Pattern = "\W"

$String -split $Pattern
#Ausgabe wie in Beispiel 3a

Beim Splitten eines Strings ist es Geschmackssache, welche Form man für die Analyse eines Strings verwendet. 

Generell bietet aber die Regex-Klasse mit ihren statischen und nicht statischen Methoden weitergehende Möglichkeiten (Optionen) an, als die Operatoren. 
Man sollte nur den Unterschied zwischen statischen und nicht statischen Methoden einer Klasse verstanden haben.

 

1.2.2 Regex-Methoden

In diesem Kapitel geht es mir um die Einsatzmöglichkeiten der vielen Methoden der Regex-Klasse. Auf die verwendeten Regularexpressions gehe ich in einem späteren Kapitel ein.  

Technet: about_Regular_Expressions

In der folgenden Tabelle stehen einige Methoden der Regex-Klasse. Im Beispiel darunter findet man den passenden Code dazu. 
MSDN: Regex-Methoden

Name Beschreibung
IsMatch Überladen. Gibt an, ob der reguläre Ausdruck eine Übereinstimmung in der Eingabezeichenfolge findet. 
Match Überladen. Durchsucht eine Eingabezeichenfolge nach einem Vorkommen eines regulären Ausdrucks und gibt das exakte Ergebnis als einzelnes Match-Objekt zurück. 
Matches Überladen. Durchsucht eine Eingabezeichenfolge nach allen Vorkommen eines regulären Ausdrucks und gibt alle erfolgreichen Übereinstimmungen wie bei einem mehrfachen Aufruf von Match zurück. 
Replace Überladen. Ersetzt in einer angegebenen Eingabezeichenfolge die mit dem Muster für den regulären Ausdruck übereinstimmenden Zeichenfolgen durch eine angegebene Ersetzungszeichenfolge. 
Split Überladen. Teilt eine Eingabezeichenfolge an den Positionen in ein Array von Teilzeichenfolgen auf, die durch eine Übereinstimmung mit einem regulären Ausdruck definiert werden. 
ToString Gibt das Muster eines regulären Ausdrucks zurück, das an den Regex-Konstruktor übergeben wurde. (Überschreibt Object..::.ToString()()().)
Unescape Entfernt alle Escapezeichen aus der Eingabezeichenfolge. 

 

Beispiel 1: Überblick

Dieses Beispiel soll als einfacher Überblick über die Anwendung der Methoden der [Regex]-Klasse  dienen. Die praxisnäheren Beispiele folgen in den nächsten Beispielen

Set-StrictMode -Version "2.0"
Clear-Host

$String = "sz karlA Kbrl KcrlNapf 3KdrlZz"
$ReplaceString = "Hugo"
$Pattern="K[a-d]rl" #True bei Karl, Kbrl, Kcrl, Kdrl  (ohne RegExOptions)
$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,"IgnoreCase")

Write-Host "`nMethode: Ismatch" -BackgroundColor DarkYellow
$IsMatch = $Regex.IsMatch($String)
"IsMatch = {0}" -f $IsMatch

Write-Host "`nMethode: Match" -BackgroundColor DarkYellow
$Match=$Regex.Match($String)
"Index: {0}  Value: {1}" -f $Match.Index,$Match.Value

Write-Host "`nMethode: Matches" -BackgroundColor DarkYellow
$Matches = $Regex.Matches($String) #Instanz der Klasse "System.Text.RegularExpressions.Match"
$Matches | ForEach{
 "Index: {0}  Value: {1}" -f $_.Index,$_.Value
 }

Write-Host "`nMethode: Replace(String,String)" -BackgroundColor DarkYellow
$Replace = $Regex.Replace($String, $ReplaceString)
$Replace

Write-Host "`nMethode: Replace(String,String,int32)" -BackgroundColor DarkYellow
$Replace = $Regex.Replace($String, $ReplaceString,2)
$Replace

Write-Host "`nMethode: Split(String)" -BackgroundColor DarkYellow
$Pattern=" "
$Regex=[Regex]$Pattern

$Split = $Regex.Split($String)
$Split.Count
$Split[2]

Write-Host "`nMethode: Split(String,int32)" -BackgroundColor DarkYellow
$Pattern = " "
$Regex = [Regex]$Pattern
$Split = $Regex.Split($String,3)
$Split
 
Write-Host "`nMethode: ToString()" -BackgroundColor DarkYellow
$Pattern = "K[a-d]rl"
$Regex = [Regex]$Pattern
$Regex.ToString()
#Ausgabe

Methode: Ismatch
IsMatch=True

Methode: Match
Index: 3  Value: karl

Methode: Matches
Index: 3  Value: karl
Index: 9  Value: Kbrl
Index: 14  Value: Kcrl
Index: 24  Value: Kdrl

Methode: Replace(String,String)
sz HugoA Hugo HugoNapf 3HugoZz

Methode: Replace(String,String,int32)
sz HugoA Hugo KcrlNapf 3KdrlZz

Methode: Split(String)
5
Kbrl

Methode: Split(String,Int32)
sz
karlA
Kbrl KcrlNapf 3KdrlZz

Methode: ToString()
K[a-d]rl

 Kapitel_3.2.2 Beispiel_1 Ueberblick.ps1.txt

 

Beispiel 2a: Prüfen, ob ein String eine formal gültige IP-Adresse darstellt

In dieser Forums-Diskussion gibt es verschiedene Lösungsansätze mit Regular Expressions. 

Powershellcommunity.org

Sehr elegant ist hieraus die Lösung von Shay Levy, diese Arbeit der .NetKlasse System.Net.IPAddress zu überlassen und nicht in ellenlangen regulären Ausdrücken unterzugehen.

Set-StrictMode -Version "2.0"
Clear-Host

$String="192.168.33.132"
#$String="2001:0db8:0000:0883:0000:8a2e:0070:7344" #funktioniert mit IP6 genauso)
[Bool]($String -as [IPAddress])
#Ausgabe 

True

Mit dem TypeOperator -as wird versucht, den String in eine IP-Adresse umzuwandeln. Durch das Casten des Ergebnisses in eine boolsche Variable erhält man True oder False als Ergebnis

Technet: about_Type Operators
MSDN: IPAddress - Klasse 

 

Beispiel 2b: Prüfen, ob ein String eine formal gültige email-Adresse darstellt

Set-StrictMode -Version "2.0"
Clear-Host

#[void][reflection.assembly]::LoadWithPartialName("System.Net.Mail") #evtl. erst die Assembly nachladen

$String = "Karl.Napf@Powershellpraxis.de"
[Bool]($String -as [System.Net.Mail.MailAddress])
#Ausgabe 
 
True

Hier gilt dasselbe, wie für Beispiel 1a.

MSDN: MailAddress - Klasse

Wenn ihr mehr Infos über gültige Mailadressen benötigt, googelt nach den Begriffen "rfc 822 email"


Beispiel 2c: Prüfen, ob ein Dateiname unzulässige Zeichen  enthält
MSDN: Naming Files, Paths, and Namespaces
  • The following reserved characters:

    • < (less than)
    • > (greater than)
    • : (colon)
    • " (double quote)
    • / (forward slash)
    • \ (backslash)
    • | (vertical bar or pipe)
    • ? (question mark)
    • * (asterisk)
Set-StrictMode -Version "2.0"
Clear-Host

Function Main{
  $FileName = "Foll*|wing`fi?e-path\con<tain's~illegalch\ars>.txt"
  $FileName = "test.txt"
 
  $InvalidHits = Check-HasFileNameInvalidChars $FileName
  If ($InvalidHits -eq $Null){
    "the fileName `n$FileName`ndoesn't contain any invalid characters "
  }Else{
    "the fileName `n$FileName`ncontains on following positions invalid characters "
     $InvalidHits | Foreach {
     Write-Host $($_.Index)  => $($_.Value)
   }#Foreach
 }#if
}#Main

Function Check-HasFileNameInvalidChars{
 Param($FileName)
 
 $InvalidFileNameChars = [System.IO.Path]::GetInvalidFileNameChars()
 $Pattern = "[$([Regex]::Escape([String]$InvalidFileNameChars))]"
 $InvalidHits = [Regex]::Matches($FileName, $Pattern)
 Return $InvalidHits
}#Check-HasFileNameInvalidChars

Main
#mögliche Ausgabe

the fileName
Foll*|wing i?e-path\con<tain's~illegalch\ars>.txt
contains on following positions invalid characters
4 => *
5 => |
10 =>
12 => ?
19 => \
23 => <
40 => \
44 => >

Ich besorge mir über die Methode GetInvalidFileNameChars() der Klasse [System.IO.Path] die invaliden Zeichen eines Dateinamens. Anschließend prüfe ich in einem regulären Ausdruck, ob einer dieser Zeichen in dem übergebenen Filenamen enthalten ist und gebe gegebenfalls Position und Zeichen aus.  

 

Beispiel 2d: Entfernen von Nicht-Ascii Zeichen aus einem String

Set-StrictMode -Version "2.0"
Clear-Host
 
$TimeWithoutHiddenCharacters = "09/15/2015 7:36 PM"
$TimeWithHiddenCharacters = "09/‎15/‎2015 7:36 PM"
 
($TimeWithoutHiddenCharacters.ToCharArray() | ForEach{[int]$_} ) -join " "
($TimeWithHiddenCharacters.ToCharArray() | ForEach{[int]$_} ) -join " "

$CleanTime = $TimeWithHiddenCharacters
#Entfernen aller nicht Asciizeichen
$Pattern = '[^\u0000-\u007F]'
$CleanTime = $TimeWithHiddenCharacters -Replace $Pattern, '' #ohne diese Zeile funktioniert ParseExact nicht
 
$Culture =[Globalization.Cultureinfo]::GetCultureInfo("en-US")
$Format = "M/dd/yyyy h:mm tt"
 
[DateTime]::ParseExact($CleanTime,$Format,$Culture)
#Ausgabe nach Entfernund der Sonderzeichen

48 57 47 49 53 47 50 48 49 53 32 55 58 51 54 32 80 77
48 57 47 8206 49 53 47 8206 50 48 49 53 32 55 58 51 54 32 80 77
 
Dienstag, 15. September 2015 19:36:00

\u0000-\u007F entspricht den Ascii-Zeichen 0-255

Das Steuerzeichen 8206 ist in dem DAtumString nicht sichtbar, verhindert dennoch das Ausführen von 
[DateTime]::ParseExact

#Ausgabe mit Sonderzeichen im Datumstring

48 57 47 49 53 47 50 48 49 53 32 55 58 51 54 32 80 77
48 57 47 8206 49 53 47 8206 50 48 49 53 32 55 58 51 54 32 80 77
Exception calling "ParseExact" with "3" argument(s): "String was not recognized as a valid DateTime."
At line:16 char:1
+ [DateTime]::ParseExact($CleanTime,$Format,$Culture)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : FormatException


Beispiel 3: Durchsuchen eines Strings auf alle Übereinstimmungen (Matches-Methode)

Set-StrictMode -Version "2.0"
Clear-Host

$String = "sz KarlA Kbrl KcrlNapf 3KdrlZz"
$Pattern = "K[a-d]rl" #True bei Karl, Kbrl, Kcrl, Kdrl
$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,"IgnoreCase") #Plus RegexOption: Ignorecase
$Matches =$Regex.Matches($String) #Instanz der Klasse "System.Text.RegularExpressions.Match"
$Matches | foreach{
    "Index: {0}  Value: {1}" -f $_.Index,$_.Value
     }
#Ausgabe

Index: 3  Value: Karl
Index: 9  Value: Kbrl
Index: 14  Value: Kcrl
Index: 24  Value: Kdrl


Beispiel 4: Mehrfach Leerzeichen in einfache Leerzeichen umwandeln

Set-StrictMode -Version "2.0"
Clear-Host

$String="sz karlA   Kbrl KcrlNapf   3Kdrl      Zz"
$ReplaceString = " "
$Pattern = "  " #doppeltes Leerzeichen
$Regex = New-Object System.Text.RegularExpressions.Regex($Pattern,"IgnoreCase")
$Regex.IsMatch($String)
"Ausgangsstring: $String"

While($Regex.IsMatch($String)){
$String = $Regex.Replace($String, $ReplaceString)
}
"Ergebnisstring: $String"
#Ausgabe

Ausgangsstring: sz karlA   Kbrl KcrlNapf   3Kdrl      Zz
Ergebnisstring: sz karlA Kbrl KcrlNapf 3Kdrl Zz

 

1.3 Regex-Options

MSDN: RegexOptions-Enumeration

[Regex]::Matches("Das,ist?nur*ein<Test","NUR","IgnoreCase")| %{$_.Value}
#Ausgabe

nur

[regex]::matches("Das,ist?nur*ein<Test","NUR","IgnoreCase")| %{$_.value}