Mustererkennung mit Regular Expressions (RegEx)
https://oer-informatik.de/regex
https://bildung.social/@oerinformatik/110397061085890869
tl/dr; (ca. 20 min Lesezeit): Die Mustererkennung Regulärer Ausdrücke (RegEx) ermöglicht Automatisierungen an Stellen, wo Handarbeit mühsam und langwierig ist. Telefonnummern in unterschiedlichen Formaten gespeichert? In einer CSV-Datei alle Spalten in verkehrter Reihenfolge? Wo stecken im Fließtext Geldbeträge mit Nachkommastellen? Derlei Aufgaben lassen sich mit RegEx lösen - besser man kennt sie! (Zuletzt geändert am 13.12.2024)
Was sind Reguläre Ausdrücke?
Ein Regulärer Ausdruck (RegEx) ist eine Zeichenkette, die Muster in Zeichenketten mithilfe von syntaktischen Regeln beschreibt.
Reguläre Ausdrücke helfen vor allem dabei, Teilstrings zu finden oder zu ersetzen, die einem einheitlichen Muster entsprechen, sich aber nicht durch einfache Wildcards (wie z.B. ? oder *) ausdrücken lassen.
So lassen sich beispielsweise relativ einfach Muster bilden, die in einem vorhandenen langen Text alle Geldbeträge, Telefonnummern, Internetlinks, EAN-Nummern oder E-Mail-Adressen finden.

Ein Einstiegs-Beispiel für eine RegEx: die Klassenbezeichnungen an unserer Schule folgen der Logik:
1. Großbuchstabe: Abteilung
2.+3. Großbuchstabe: Ausbildungsberuf
4. Zahl: Einschulungsjahr (letzte Stelle)
5. Großbuchstaben für Parallelklassen
==> 3 Großbuchstaben, eine Zahl, ein Großbuchstabe
Ein Regulärer Ausdruck, der das beschreiben würde, wäre beispielsweise:
[A-Z][A-Z][A-Z][0-9][A-Z]
Es wurden einfach fünf Zeichenklassen hintereinander geschrieben. Das geht noch einfacher:
[A-Z]{3}[0-9][A-Z]
[A-Z]
definiert hier die Zeichenklasse der Großbuchstaben (alle Zeichen, die in der ASCII/Unicode-Tabelle zwischenA
undZ
stehen)[0-9]
die Zeichenklasse der Zahlen (ASCII zwischen 0 und 9){3}
definiert das mehrfache Vorkommen der Zeichenklasse (ein Quantifizierer).
Suchmuster bestehen also in erster Linie aus Aneinanderreihungen von Zeichenklassen und Quantifizierern.
Grundlagen: Einfache RegEx
Die beiden Grundlagen habe wir ja oben bereits kennengelernt: Zeichenklassen und Quantifizierer. Schauen wir uns diese Elemente mal etwas genauer an:
Definition von Zeichenklassen
Die einfachste Art, Zeichenklassen zu definieren, ist es, alle Zeichen, die man finden will, in eckige Klammern zu schreiben. Die Inhalte in der eckigen Klammer sind ODER-verknüpft.
RegEx | Erläuterung |
---|---|
[aeiou] ,[a-z] ,[A-Z] ,[0-9] , [a-zA-Z0-9] |
Zeichenklassen passen auf ein Zeichen, das in der Klasse enthalten ist.[aeiou] passt auf a, e, i, o oder u, aber nicht auf x. Es können auch Bereiche angegeben werden,[a-z] passt auf alle Kleinbuchstaben. [a-zA-Z0-9] Bereiche können auch kombiniert werden.Die Sonderzeichen verlieren in einer Klasse ihre Wirkung: Punkt, Stern, Fragezeichen (siehe oben: Metacharaktere) |
[^abc] , [^a-z] ,[^a-zA-Z0-9] |
^ negiert die Zeichenklassen:[^abc] passt auf jedes beliebige Zeichen, außer a, b und c.(!! außerhalb der [ ] steht ^ für Eingabebeginn!! s.o.) |
[a-z&&[^mn]] |
Verschachtelung und Ausschluss: a bis z außer m und n |
Quantifizierer: Häufigkeit des Auftretens (außerhalb der Zeichenklassendefinition!)
RegEx | Erläuterung |
---|---|
* |
Das vorangehende Element (ein einzelnes Zeichen, eine geklammerte Zeichenfolge oder eine Zeichenklasse) darf beliebig oft vorkommen, auch keinmal. |
+ |
Das vorangehende Element muss mindestens einmal, darf aber auch öfter vorkommen. |
? |
Das vorangehende Element darf nicht oder genau einmal vorkommen, aber keinesfalls öfter. |
{n} |
Das vorangehende Element muss genau n-mal vorkommen. |
{n,} |
Das vorangehende Element muss mindestens n-mal vorkommen. |
{n, m} |
Das vorangehende Element muss mindestens n-mal aber höchstens m-mal vorkommen. |
{,m} |
Das vorangehende Element darf höchstens m-mal vorkommen. (geht bei wenigen Parsern) |
Lazy / Greedy
Reguläre Ausdrücke mit den Quantifizierern *
und +
sind gierig (greedy): sie versuchen, so viel wie möglich Treffer zu erzielen und das Suchmuster über möglichst viele Zeichen auszudehnen. In der Regel ist dies jedoch nicht gewünscht: Bestimmte Zeichenklassen sollen sich nur so lange wiederholen, bis das erste Vorkommen der folgenden Zeichenklasse auftritt. Diese genügsamere Suchcharakteristik (lazy) lässt sich umstellen, in dem die lazy Varianten der Multiplizität genutzt werden (*?
und +?
): Das Fragezeichen kommt hier als Metacharakter erneut zum Zug:
Beispieltext | greedy RegEx | lazy RegEx |
---|---|---|
<kunden><kunde></kunde></kunden> |
<.*> findet Gesamttext |
<.*?> findet nur <kunden> |
Es gibt kein richtiges Leben im falschen |
E.+n findet Gesamttext |
E.+?n findet Es gibt kein |
dadada |
(da){1,} findet dadada |
(da){1,}? findet drei mal da |
Literale und Metacharaktere als Elementarbausteine
In Regulären Ausdrücken wird zwischen Literalen und Metacharakteren unterschieden: Literale repräsentieren das jeweilige Zeichen, Metacharaktere haben eine syntaktische Bedeutung. Alle Zeichen, die Metacharaktere repräsentieren, lassen sich über einen Backslash maskieren und repräsentieren so das eigentliche Zeichen (z.B. \[
für die eckige Klammer).
Zeichen | Metacharakter Bedeutung innerhalb einer Zeichenklasse [ ] |
Metacharakter Bedeutung außerhalb einer Zeichenklasse |
---|---|---|
. |
beliebiges Zeichen | |
^ |
Negierung[^a] : kein a |
Beginn der Eingabe |
$ |
Ende der Eingabe | |
? |
0-1-mal (Quantifizierer {0,1} )(? ...) leitet Direktiven ein |
|
* |
* : 0-n-mal (Quantifizier {0,} )*? : lazy-Variante |
|
+ |
1-n-mal (Quantifizier {1,} )+? : lazy-Variante |
|
| |
oder | |
[ |
Klassenbeginn | |
] |
Klassenende | |
{ } |
von - bis mal (Quantifizierer) | |
( ) |
Gruppierung | |
\ |
Maskierung | Maskierung |
/ |
Begrenzung der RegEx | |
- |
Bereichskennzeichnung |
Immer dann, wenn für ein Zeichen in der obigen Tabelle eine Metacharakterbedeutung zugewiesen ist, muss das Zeichen maskiert werden, wenn es als Literal gesucht werden soll.
Übersicht vordefinierter Zeichenklassen
Vordefinierte Zeichenklassen
RegEx | Erläuterung |
---|---|
. |
Der Punkt passt auf ein beliebiges Zeichen (bei vielen Parsern: bis auf Newline) |
\d = [0-9] \D = [^0-9] |
digit: Vordefinierte Zeichenklassen für Ziffern. \d passt auf alle Ziffern, entspricht also genau [0-9] . (\D ist genau das Gegenteil und passt auf alles außer Ziffern.) |
\t , \n , \r |
Tabulator, linefeed (Zeilenvorschub, LF), carriage return (Wagenrücklauf, CR) *nix nutzen \n als Zeilenumbruch, Windows \r\n |
\s = nicht \S |
whitespace: \s ist eine vordefinierte Klasse, die auf Whitespaces passt, also Leerzeichen, Zeilenumbruch, Tabulator usw. [\t\n\x08\x0c\r] (\S ist wieder das Gegenteil) |
\w = [a-zA-Z_0-9] = nicht \W |
word: \w entspricht [a-zA-Z_0-9] , ob Umlaute erkannt werden können, hängt von der Systemkonfiguration ab (\W ist die Negation davon) |
\b = nicht \B |
Wortgrenze, also Tabulator, Leerzeichen |
\xhh |
Zeichen mit Hexadezimalwert hh |
\uhhhh \N{EURO SIGN} |
Unicodezeichen mit Hexcode hhhh bzw. in Unicode-Notation |
Position und Grammatik (außerhalb der Zeichenklassendefinition!)
RegEx | Erläuterung |
---|---|
^ |
start of string anchor: Anfang der Eingabe. ^ana passt in ananas , aber nicht in banane . |
$ |
end of string anchor: Ende der Eingabe. ze$ passt in Katze , aber nicht in Katzen . |
\A \Z |
Stringbeginn und -ende |
\< \> |
Wortbeginn und -ende |
\| |
Oder-Verknüpfung, entweder der Ausdruck links oder der Ausdruck rechts muss passen. |
() |
Mit Klammern gruppierte und selektierte Reguläre Ausdrücke können in der Reihenfolge gezielt ausgegeben werden: Ausgabe im RegEx über \1 (erste Klammer) \2 usw… (parserabhängig auch $1 $2 usw.) oder per Java über den matcher.group(1) |
(?<wert>) |
Selektierte Ausdrücke können auch mit einem Namen versehen werden (hier: wert ) und über diesen im Matcher (z.B. Java) gezielt angesprochen werden: (?<wert>[0-9.,]+)\\s*(?<waehrung>[A-Z]{3}) |
matcher.group("wert") |
|
(?:) |
Ausdruck wird gruppiert, ist aber nicht selektiv ansprechbar. (geht bei wenigen Parsern) |
(?=) |
Ausdruck: “Muss gefolgt werden von” Ausdruck vor der Klammer muss gefolgt werden von Ausdruck in der Klammer. Letzterer wird aber nicht in das Ergebnis geschrieben. |
(?!) |
Ausdruck: “Darf nicht gefolgt werden von” (entsprechend wie oben) |
POSIX-Zeichenklassen
RegEx | Erläuterung |
---|---|
\p{Lower} |
ASCII Kleinbuchstabe: [a-z] |
\p{Upper} |
ASCII Großbuchstabe: [A-Z] |
\p{ASCII} |
ASCII Zeichen: [\x00-\x7f] |
\p{Alpha} |
Buchstabe: [A-Za-z] |
\p{Digit} |
Ziffer: \d |
\p{Alnum} |
Buchstabe oder Ziffer |
Unicode-Zeichenklassen
RegEx | Erläuterung |
---|---|
\p{Lu} |
Unicode Großbuchstabe |
\p{Ll} |
Unicode Kleinbuchstabe |
\p{Sc} |
Unicode Währungssymbol |
\p{Nl} |
Unicode Zahl oder Buchstabe |
Flags
RegEx | Erläuterung |
---|---|
(?i) |
Case-insensitive (ASCII) |
(?iu) |
Case-insensitive (Unicode) |
(?g) |
global match |
(?m) |
Multi-line mode |
(?s) |
Single-line / dotall mode |
Beispiele zum Verständnis
CSBME
findet exakt die Zeichenkette CSBME^CSBME$
findet eine Zeile, die ausschließlich aus der Zeichenkette CSBME besteht(Hund|Katze|Maus)
findet die Wörter Hund oder Katze oder Maus[Hund|Katze|Maus]
die BuchstabenHKMadenstuz
sowie die Pipe[0-9]{2}-[0-9]{2}-[0-9]{4}
findet ein Datum der Notation01-01-2000
- suche:
([0-9]{2})-([0-9]{2})-([0-9]{4})
ersetze:\1\.\2\.\3
wandelt ein Datum von der Form 01/01/2000 in die Form 01.01.2000 um.
RegEx in Programmiersprachen nutzen:
Text suchen
Python bietet mit re
eine Library, die das Handling für Reguläre Ausdrücke komfortablen übernimmt:
import re
text = "Ist hier eine Postleitzahl in acht Wörtern versteckt?"
if (re.search("[0-9]{5}, text)):
# Text enthält Zahlen
pass
import re
text = "Ist hier eine Postleitzahl in acht Wörtern versteckt?"
ergebnisliste = re.findall("[acehinr]+", text)
print(ergebnisliste)
Text aufteilen
import re
text = "Ist hier eine Zahl in acht Wörtern versteckt?"
ergebnisliste = re.split("[in]+", text)
print(ergebnisliste)
Text ersetzen
import re
text = "Drei Flötisten mit dem Kontrabass."
ergebnis = re.sub("[aeiouAEIOUÄÖÜäöü]+", "u", text)
print(ergebnis)
Teile eines Suchmusters ersetzen
import re
text = "030kleinbuchstabenersetzenDASHIERNICHT."
ergebnis = re.sub("([0-9]*)([^A-Z]*)([A-Z]*)", r'\g<1> neuer Text \g<3> \g<2>', text)
print(ergebnis)
Die im ersten String mit Klammern gruppierten Gruppenergebnisse können über \g<1>
bis \g<n>
der Reihe nach referenziert werden. \g<0>
referenziert den gesamten gefundenen Ausdruck. Das führende r
bei r'\g<1>...'
setzt den String in den raw-Mode, auf diese Art müssen Schrägstriche nicht maskiert werden.
Mithilfe dieser Funktion können komplexe Suchen/Ersetzen-Aufgaben erledigt werden. Obiges Programm/Pattern gibt beispielsweise 030 neuer Text DASHIERNICHT kleinbuchstabenersetzen
aus.
RegEx in Powershell und Bash
Mit RegEx über das Terminal nach Dateiinhalten suchen
Beispiel: in einer Datei befindet sich irgendwo ein ungewöhnliches Zeichen, weswegen die Datei nicht verarbeitet werden kann. Folgende Aufrufe mit regulären Ausdrücken finden die betreffenden Zeilen:
Mit RegEx über das Terminal Dateiinhalte verändern
In einer Textdatei soll bei allen Geldbeträgen, die mit EUR
enden das Zeichen € gesetzt werden. Da im Text auch an anderen Stellen EUR
steht, muss sichergestellt werden, dass nur bei den Geldbeträgen die Währungsbezeichnung ersetzt wird. Folgender Aufruf ändert das direkt in der Datei:
Noch kein Beispiel für die Powershell vorhanden
RegEx in SQL-Abfragen
PostgreSQL bietet mit den Funktionen regexp_instr()
und regexp_like()
Möglichkeiten, die Mustererkennung komfortabel durchzuführen. Weitere Infos dazu unter diesem Link.
Links und weitere Informationen
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Mustererkennung mit Regular Expressions (RegEx)” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/regex veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/regex/regex-basics. Stand: 13.12.2024.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]