Regex, Überblick, Begriffe, Parameter, Grundlagen und Beispiele
Regex ist eine universelle Beschreibungssyntax um bestimmte Teile aus Zeichenketten zu prüfen oder zu filtern. Als Beispiel könnten mit Regex sehr einfach alle <h1>-Überschriften aus einem HTML-Quellcode herausgefiltert werden. Angefangen mit PHP, habe ich Regex später auch in PowerShell und JavaScript eingesetzt. Zugegeben, anfangs habe ich Beispiele aus dem Internet für meine Einsatzzwecke angepasst und diese nur teilweise verstanden, zumal die Regex-Syntax doch irgendwie anders war, als alles mir bis dahin Bekannte. Einmal etwas tiefer damit beschäftigt, bietet Regex aber ein mächtiges Werkzeug für String Prüfungen oder Filter jeglicher Art. Mit Regex können bestimmte String-Operationen wesentlich einfacher, effizienter und eleganter umgesetzt werden. Ursprünglich in Perl eingesetzt, kann die Syntax mittlerweile zu großen Teilen in allen gängigen Skriptsprachen verwendet werden: Gängige Skriptsprachen unterstützen den Standard PCRE (Perl Compatible Regular Expressions) oder lehnen sich zumindest an dessen Syntax an.
Auch wenn die Theorie nicht unwesentlich ist, verstehe ich all jene die sich vorab lieber konkrete Beispiele ansehen wollen. Ich habe auf dieser Seite Regex-Beispiele für PHP, JavaScript und PowerShell zusammengestellt:
- PHP regex - Beispiele
- Die Beispiele dieses Artikels wurden in folgendem Artikel auf JavaScript übersetzt: Javascript regex - Beispiele
- PowerShell regex - Beispiele (auch für PowerShell wurden die Beispiele dieses Artikels übersetzt)
Die Ergebnisse der hier verwendeten Beispiele wurden mit PHP: preg_match_all oder preg_replace erzeugt und sind auch für andere Skriptsprachen gültig. Wenn die preg_match_all-Ausgabe zusätzliche Zeichenketten im Ergebnis-Array enthält, handelt es sich standardmäßig um Werte für das erste eingeklammerte Teilsuchmuster, diese werden hier, falls vorhanden, als Treffer-Gruppe1 gelistet.
Nun aber zu den Grundlagen, um Regex schneller und effizienter nutzen zu können, hier ein Überblick über die Zusammensetzung der Regex-Syntax.
Regex - Zusammensetzung
(auch mehrfach hintereinander möglich: "und" bzw. mit | "oder") |
|
|||||
Delimiter / Trennzeichen | Zeichenklasse | Delimiter / Trennzeichen | ||||
/ ~ @ ; % ` # |
/ ~ @ ; % ` # |
Für die meisten Skriptsprachen wird die Regex-Such-Syntax zwischen 2 Trennzeichen (Delimiter) geschrieben ( /
oder ~
oder @
...) und am Ende der Syntax können Optionen angegeben werden. Eine Ausnahme dazu ist PowerShell. In PowerShell kann für Regex direkt die Zeichengruppe verwendet und die Option über eine Eigenschaft des Regex-Objektes festgelegt werden, siehe Regex PowerShell Optionen.
Zeichengruppen - Zeichenauswahl
In regulären Ausdrücken entsprechen die meisten Zeichen sich selbst. Als Beispiel führt das Suchen im String "ich lerne Regex", mit dem Suchbegriff "lerne", zu einem Treffer. Zusätzlich können die zu suchenden Zeichen in einer Zeichenklasse innerhalb von [ und ] zusammengefasst werden.
Zum Beispiel entspricht eine Zeichenklasse [abc]
den folgenden Zeichen: a
, b
oder c
. Beispiel: String: abcdefghijk...
Suchpattern: [abc]
Treffer:
a
b
c
[a-z]
entspricht a,b,c,d, ... z. Beispiel: String: abcdefghijklmnopqrstuvwxyz
Suchpattern: [a-z]
Treffer:
a
b
c
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
Zeichenklassen können mit ^
negiert werden: [^abc]
entspricht alles außer a,b,c. Beispiel: String: abcdefghijklmnopqrstuvwxyz
Suchpattern: [^abc]
Treffer:
d
e
f
g
h
i
j
k
l
m
n
o
p
q
r
s
t
u
v
w
x
y
z
Die Zeichengruppen können beliebig kombiniert werden, indem diese einfach hintereinander geschrieben werden:
[a][0-9]
... entspricht einem a mit darauffolgend einer Zahl von 0-9: a0, a1, .... Beispiel: String: a1b2c3
Suchpattern: [a][0-9]
Treffer:
a1
Für ein "oder" kann ein |
verwendet werden:
[a]|[0-9]
... entspricht einem a oder einer Zahl von 0-9; Beispiel: String: a1b2c3
Suchpattern: [a]|[0-9]
Treffer:
a
1
2
3
Um in Regex einen Kommentar zu schreiben, kann dieser innerhalb (?# und ) hinterlegt werden, als Beispiel: String: ich lerne Regex Suchpattern: lerne(?#lerne steht für sich selbst) Treffer: lerne
Hier nochmal zusammengefasst:
Ausdruck | Beschreibung | Beispiel |
---|---|---|
text | Ein Text entspricht sich selbst | String: ich lerne Regex Suchpattern: lerne Treffer: lerne |
[abc] | nach bestimmten Zeichen suchen | String: abcdefghijk... Suchpattern: [abc] Treffer: a b c |
[a-z] | Zeichen von bis .. | String: abcdefghijklmnopqrstuvwxyz Suchpattern: [a-z] Treffer: a b c d e f g h i j k l m n o p q r s t u v w x y z |
[^abc] | Alle Zeichen außer den angeführten | String: abcdefghijklmnopqrstuvwxyz Suchpattern: [^abc] Treffer: d e f g h i j k l m n o p q r s t u v w x y z |
[0-9\.\-] | 0,1,2,3,4,5,6,7,8,9,.,- Nummer, Punkt oder Minus | String: Text mit 123-312.123 Suchpattern: [0-9\.\-] Treffer: 1 2 3 - 3 1 2 . 1 2 3 |
([ab])([cd]) | ac, ad, bc, oder bd | String: abcdefgh Suchpattern: ([ab])([cd]) Treffer-Gruppe0: bc Treffer-Gruppe1: b |
a|b | oder | String: abcdefgh Suchpattern: a|b Treffer: a b |
[^A-Za-z0-9] | Symbole die kein Buchstabe oder keine Zahl sind | String: ab!cdefg?h Suchpattern: [^A-Za-z0-9] Treffer: ! ? |
Neben "[
", "-
", "|
" und "^
" haben auch andere Zeichen eine besondere Bedeutung:
Zeichen mit speziellen Funktionen - Escapezeichen (Character Escapes)
Folgende Zeichen haben in Regex eine spezielle Funktion: \.*?+-[]{}|()^$
.
Um diese Zeichen in Regex als Zeichen verwenden zu können, müssen diese mit einem vorangehenden \ versehen werden. Für \ also \\
, bei einem Fragezeichen \?
usw.
Zeichenklassen (Character Classes)
Zeichenklasse | Beschreibung | Entspricht der [ ] - Zeichenklasse | Beispiel |
---|---|---|---|
. | bedeutet ein alphanumerisches Zeichen. | String: Beispiel-String Suchpattern: . Treffer: B e i s p i e l - S t r i n g | |
\d | Dezimalziffer | [0-9] | String: A847 Suchpattern: \d Treffer: 8 4 7 |
\D | keine Dezimalziffer | [^0-9] | String: A847 Suchpattern: \D Treffer: A |
\w | ein Buchstabe, Zahl oder Unterstrich | [a-zA-Z_0-9] | String: B??spiel Suchpattern: \w Treffer: B s p i e l |
\W | kein Buchstabe, Zahl oder Unterstrich | [^a-zA-Z_0-9] | String: B%?spiel Suchpattern: \W Treffer: % ? |
\s | Leerzeichen | String: Beispiel String Suchpattern: \s Treffer: | |
\S | kein Leerzeichen | String: Beispiel String Suchpattern: \S Treffer: B e i s p i e l S t r i n g |
Quantifizierer
Die folgenden Zeichen beeinflussen, wie oft ein Muster entsprechen soll. Die Quantifizierrer werden dazu an die Zeichengruppen oder Zeichenklassen angehängt:
Quantifizierer | Beschreibung | Beispiel |
---|---|---|
+ | bedeutet eines oder mehrere der vorherigen Ausdrücke | String: String Suchpattern: [A-Z]+ Treffer: S |
* | bedeutet keines oder mehrere der vorherigen Ausdrücke (.* bedeutet also keines oder mehrere alphanumerische Zeichen. ) |
String: String Suchpattern: .* Treffer: String
|
? |
keines oder eines der vorherigen Ausdrücke; Non-Greedy = Lazy Matching, siehe auch: Greedy vs Non-Greedy |
String: String Suchpattern: [A-Z]? Treffer: S |
{} |
{3} genau 3 Vorkommen der vorherigen Ausdrücke {3,} 3 oder mehrere Vorkommen der vorherigen Ausdrücke {a,b} entspricht dem vorherigen Zeichen wenn es a-mal vor kommt, aber nicht öfter als b-mal. |
String: String Suchpattern: .{3} Treffer: Str ing |
Greedy vs Non-Greedy oder Lazy Matching
Standardmäßig versucht Regex soviele Daten wie möglich zu finden: Greedy. Das Verhalten lässt sich am einfachsten mit einem konkreten Beispiel erklären:
Beim Extrahieren von HTML-Tags aus HTML würde per Default nur ein Treffer, zwischen dem ersten und dem letzten Tag, ausgegeben werden:
String: <html><head></head><body><h1>First Headline</h1><p>Text</p><h1>Second Headline</h1></body></html>
Suchpattern: <h1>(.*)</h1>
Treffer-Gruppe0:
<h1>First Headline</h1><p>Text</p><h1>Second Headline</h1>
Treffer-Gruppe1:
First Headline</h1><p>Text</p><h1>Second Headline
Für das Extrahieren von einzelnen HTML-Tags ist das Verhalten so nicht brauchbar. Abhilfe schafft das Hinzufügen eines ?
im Suchpattern: Regex verarbeitet den String dann "Non-Greedy", auch Lazy Matching genannt:
String: <html><head></head><body><h1>First Headline</h1><p>Text</p><h1>Second Headline</h1></body></html>
Suchpattern: <h1>(.*?)</h1>
Treffer-Gruppe0:
<h1>First Headline</h1>
<h1>Second Headline</h1>
Treffer-Gruppe1:
First Headline
Second Headline
letzter Treffer
Um nach dem letzten Treffer zu suchen, kann eine negative Suche hinzugefügt werden:
String: <h1>First Headline</h1><h1>Second Headline</h1><h1>Third Headline</h1> Suchpattern: .*<h1>(.*?)</h1>(?!(\s|.)*<) Treffer-Gruppe0: <h1>First Headline</h1><h1>Second Headline</h1><h1>Third Headline</h1> Treffer-Gruppe1: Third Headline
Erklärung der zusätzlichen negativen Suche: (?!(\s|.)*<)
\s
.. enspricht: Tabs, Leerzeichen, Linebreaks
(\s|.)
.. Tabs, Leerzeichen, Linebreaks oder ein beliebiges Zeichen
(\s|.)*
.. beliebig viele Tabs, Leerzeichen, Linebreaks oder Zeichen
(\s|.)*<
.. beliebig viele Tabs, Leerzeichen, Linebreaks oder Zeichen gefolgt von einem <
?!
.. negative Suche: wenn der Treffer nicht zutrifft: also
(?!(\s|.)*<
.. wenn keine Tabs, Leerzeichen, Linebreaks oder Zeichen mit anschließendem <
vorkommen: was als Auswahl dem letzten <h1>
-Tag entspricht, bei allen anderen <h1>
-Tags folgt noch ein weiterer <
-Tag ..
Anker: Anchors
Anchors beschreiben die Position im String in welcher der Treffer vorkommt
Anchor | Beschreibung | Beispiel |
---|---|---|
^ | sucht zu Beginn des Strings |
String: Beispiel-String Suchpattern: ^[A-Za-z] Treffer: B |
$ | Sucht am Ende des Strings |
String: Beispiel-String Suchpattern: [A-Za-z]$ Treffer: g |
\A | Der Treffer muss am Beginn eines Strings auftreten |
String: Beispiel-String Suchpattern: \A[A-Za-z] Treffer: B |
\z | Der Treffer muss am Ende eines Strings auftreten |
String: Beispiel-String Suchpattern: [A-Za-z]\z Treffer: g |
\Z | Der Treffer muss am Ende eines Strings auftreten oder vor \n am Ende eines Strings |
String: Beispiel-String Suchpattern: [A-Za-z]\Z Treffer: g |
\G |
Der Treffer startet an der Position, an der der vorige Treffer endet. \G zwingt das Muster, nur Übereinstimmungen zurückzugeben, die Teil einer fortlaufenden Kette von Übereinstimmungen sind. Ab dem ersten Treffer muss jedem nachfolgenden Treffer ein Treffer vorausgehen. Wenn die Kette unterbrochen wird, enden die Treffer. |
Folgendes Beispiel stoppt die Treffer nach dem 2ten "match": String: match,match,not-match,match Suchpattern: (\Gmatch), Treffer-Gruppe0: match, match, Treffer-Gruppe1: match match Im Vergleich, ohne \G würde der letzte Treffer auch verarbeitet werden: String: match,match,not-match,match Suchpattern: (match), Treffer-Gruppe0: match, match, match, Treffer-Gruppe1: match match match |
\b | Der Treffer muss an einer Wortgrenze auftreten | String: Beispiel String Suchpattern: [A-Za-z]\b Treffer: l g |
\B | Der Treffer muss nicht an einer Wortgrenze auftreten | String: Beispiel String
Suchpattern: [A-Za-z]\B
Treffer:
B
e
i
s
p
i
e
S
t
r
i
n
|
Gruppieren : Gruppierungskonstrukte (Grouping Constructs)
Das Zeichen |
wird für "oder" verwendet. Zudem können Zeichen zusätzlich gruppiert werden: h(a|e)llo
entspricht hallo oder hello
Ausdruck | Beschreibung | Beispiel |
---|---|---|
( Subausdruck ) |
Erfasst den übereinstimmenden Unterausdruck und weist ihm eine einbasierte Ordnungszahl zu. |
String: Teesst Suchpattern: (\w)\1 Treffer-Gruppe0: ee ss Treffer-Gruppe1: e s Erklärung \1: \Nummer : Rückverweis. Entspricht dem Wert eines nummerierten Unterausdrucks. |
(?<name>Subausdruck) |
Erfasst den übereinstimmenden Unterausdruck in einer benannten Gruppe. |
String: Teesst Suchpattern: (?<doppelt>\w)\k<doppelt> Treffer-Gruppe0: ee ss Treffer-Gruppe1: e s Erklärung \k<Name>: Benannter Rückverweis. Entspricht dem Wert eines benannten Ausdrucks. String: Te12e12st Suchpattern: (?<doppelt>e[0-9]{2})\k<doppelt> Treffer-Gruppe0: e12e12 Treffer-Gruppe1: e12 |
(?=suche) | positiv Lookahead: finde Ausdruck A wenn Ausdruck B folgt. | String: 33 und 44X. Suchpattern: [0-9]{1,}(?=X) Treffer: 44 |
(?<=suche) | positiv Lookbehind | String: X33 und 44 Suchpattern: (?<=X)[0-9]{1,} Treffer: 33 |
(?!=suche) | negativ Lookahead: finde Ausdruck A wenn Ausdruck B nicht folgt. | String: 2ac4b Suchpattern: [0-9](?!b) Treffer: 2 |
(?<!suche) | negativ Lookbehind | String: Nummer9 hat kein a vor der Nummer a8 schon Suchpattern: (?<!a)[0-9] Treffer: 9 |
(?( Ausdruck ) ja | nein ) |
if, then, else: |
String: X10 B90 Y524 123 Suchpattern: (?(?=B)B[0-9]{2}\b|\b[0-9]{3}\b) Treffer: B90 123 |
(?<Name>Ausdruck )?( ja | nein ) der Ausdruck kann in ja mit |
if, then, else |
String: X10 B90 Y524 123 Suchpattern: (?<BWert>B)?(?(<BWert>)[0-9]{2}\b|\b[0-9]{3}\b) Treffer-Gruppe0: B90 123 Treffer-Gruppe1: B String: X10 4B90 Y524 123 Suchpattern: (?<BWert>[0-9]B)?(?(<BWert>)[0-9]{2}\b|\b[0-9]{3}\b) Treffer-Gruppe0: 4B90 123 Treffer-Gruppe1: 4B |
Ersetzungen (Substitutions)
Ausdruck | Beschreibung | Beispiel |
---|---|---|
$Nummer | Anhand von Gruppennummern ersetzen |
String: eins zwei Suchpattern: \b(\w+)(\s)(\w+)\b ersetzen: $3$2$1 Ergebnis: zwei eins Bei nur einem Treffern wird $0 verwendet. |
${Name} | Anhand von Gruppennamen ersetzen | In PHP nicht supported |
Optionen
Option | Beschreibung |
---|---|
g | Global: Nach dem ersten Suchtreffer weitersuchen |
i | Groß- und Kleinschreibung gleich behandeln. |
m | Mehrzeilenmodus |
s | Mit dieser Option kann ein Punkt für alle Arten von Zeichen verwendet werden: Inklusive Zeilenumbrüche |
x | ignoriert alle Leerraumzeichen im Suchmuster. |
Regex - Praxis-Beispiele für bestimmte Skriptsprachen
{{percentage}} % positiv