Reguläre Ausdrücke verstehen und anwenden
Ein regulärer Ausdruck, kurz Regex, beschreibt ein Muster für Zeichenketten. Damit kannst du Text durchsuchen, Eingaben prüfen oder Bestandteile ersetzen. Entscheidend ist, welches Zeichen ein Musterelement beschreibt, worauf ein Quantor wirkt und ob du einen Teiltreffer oder die gesamte Zeichenkette prüfen möchtest.
Hake ab, was du schon kannst — und komm am Ende hierher zurück!
Vom Text zum Muster
Stell dir vor, du suchst in vielen Zeichenketten nach einer bestimmten Form. Ein einzelnes Wort wie abc ist bereits ein einfaches Muster: Es trifft die genaue Zeichenfolge abc, auch als Teil einer längeren Zeichenkette.
Regulärer Ausdruck
Ein regulärer Ausdruck ist eine nach festen Regeln aufgebaute Beschreibung einer Menge von Zeichenketten. Beim Pattern Matching wird geprüft, ob ein Text oder ein Teil davon zu diesem Muster passt.
Ein Regex besteht aus zwei Arten von Zeichen:
- Literale stehen für sich selbst. Im Muster
TagmüssenT,aundgin dieser Reihenfolge vorkommen. - Metazeichen haben eine besondere Funktion. Dazu gehören beispielsweise
.,*,+,?,|,(,),[und].
Das Muster ab*c verlangt ein a, danach beliebig viele b und anschließend ein c. Es passt daher zu ac, abc und abbbbc.
Lies ein Regex von links nach rechts. Bestimme zuerst die einzelnen Musterelemente und danach die Wirkung von Gruppen und Quantoren.
Zeichen auswählen und wiederholen
Eine Zeichenklasse beschreibt genau ein Zeichen aus einer Auswahl. [abc] trifft also ein a, ein b oder ein c.
Bereiche verkürzen eine Auswahl:
[0-9]steht für eine Ziffer von0bis9.[a-c]steht füra,boderc.[A-Za-z]steht für einen der ausdrücklich angegebenen Groß- oder Kleinbuchstaben.[^u]steht für ein einzelnes Zeichen außeru.
Der Punkt . ist in vielen Dialekten ein Platzhalter für fast jedes Einzelzeichen. Ob er auch einen Zeilenumbruch erfasst, hängt vom verwendeten Modus ab.
Ein Quantor bestimmt, wie oft das unmittelbar vorherige Element vorkommen darf:
*: null oder mehr Wiederholungen+: eine oder mehr Wiederholungen?: null oder eine Wiederholung{n}: genaunWiederholungen{n,m}: mindestensn, höchstensmWiederholungen{n,}: mindestensnWiederholungen
Gesucht ist eine Hausnummer mit einer bis drei Ziffern ohne führende Null und einem optionalen Kleinbuchstaben.
Das Muster lautet:
[1-9][0-9]?[0-9]?[a-z]?
Der erste Teil [1-9] ist verpflichtend. Die beiden folgenden Ziffernklassen tragen jeweils ? und sind daher optional. Auch der Kleinbuchstabe ist optional.
Damit passen beispielsweise 7, 42, 128 und 12a. 012 passt nicht, weil die erste Ziffer keine Null sein darf. 1234 enthält eine Ziffer zu viel, wenn die gesamte Zeichenkette geprüft wird.
Klammern verändern, worauf ein Quantor wirkt. (ab)+ wiederholt den vollständigen Block ab; das Muster passt beispielsweise zu ab und abab. Ohne Klammern würde ab+ nur das b wiederholen.
Wähle in jeder Lücke die passende Form und prüfe anschließend deine Antworten.
Ein Quantor wirkt auf das unmittelbar ein. Der Stern erlaubt Wiederholungen. Die Klasse [0-9] beschreibt . Im Muster (ab)+ wird die wiederholt.
Teiltreffer und vollständige Eingaben unterscheiden
Viele Suchfunktionen melden bereits einen Treffer, wenn nur ein Teil des Textes passt. [0-9]{2,5} findet in 1234507 beispielsweise die Teilzeichenkette 12345.
Soll die gesamte Zeichenkette aus zwei bis fünf Ziffern bestehen, werden in vielen Dialekten Anfang und Ende markiert:
^[0-9]{2,5}$
^ bezeichnet gewöhnlich den Anfang und $ das Ende der untersuchten Zeichenkette oder Zeile. Die genaue Bedeutung kann sich durch den Mehrzeilenmodus ändern. Manche Programmierschnittstellen bieten deshalb eine eigene Ganzstring-Prüfung an.
Für das Muster ^[0-9]{2,5}$ gilt:
42passt: zwei Ziffern.54072passt: fünf Ziffern.7passt nicht: zu kurz.123450passt nicht: zu lang.a42passt nicht: Es enthält einen Buchstaben.
Ein Sonderzeichen muss geschützt werden, wenn du es als gewöhnliches Zeichen suchst. Der Punkt bedeutet normalerweise „beliebiges Zeichen“. \. verlangt dagegen einen echten Punkt. Das Muster 11\.10\.2019 passt deshalb zum Datum mit Punkten, aber nicht zu 11a10b2019.
Frage vor dem Testen: Suche ich einen passenden Ausschnitt oder soll die gesamte Eingabe dem Muster entsprechen?
Alternativen, Gruppen und Trefferauswahl
Der senkrechte Strich | trennt praktische Alternativen. Baum|Blume passt zu Baum oder Blume.
Klammern fassen mehrere Elemente zusammen. (Sonn|Frei)tag passt zu Sonntag oder Freitag. Ohne passende Gruppierung könnte die Alternative einen größeren Bereich erfassen als beabsichtigt.
Gruppen können in vielen Engines außerdem den gefundenen Text speichern. Eine solche Capturing-Gruppe lässt sich später beim Ersetzen oder über eine Rückwärtsreferenz wiederverwenden. Benötigst du den gespeicherten Teil nicht, unterstützen viele Dialekte eine nicht erfassende Gruppe wie (?:ab).
Gierig und zurückhaltend suchen
Quantoren sind gewöhnlich gierig: Sie erfassen zunächst so viel wie möglich, solange der Rest des Musters noch passen kann.
Auf dem Text ABCDEB trifft A.*B die gesamte Zeichenkette ABCDEB.
In Dialekten mit zurückhaltenden Quantoren trifft A.*?B dagegen nur AB, weil der Treffer beim ersten möglichen B endet.
Auch A[^B]*B endet hier beim ersten B: Die negierte Zeichenklasse erlaubt zwischen Anfang und Ende kein weiteres B.
Zurückhaltende und possessive Quantoren, Capturing, Rückwärtsreferenzen und Look-arounds sind Erweiterungen praktischer Engines. Ihre genaue Schreibweise und Unterstützung unterscheiden sich.
Reguläre Ausdrücke als formale Sprachbeschreibung
In der theoretischen Informatik beschreibt ein regulärer Ausdruck nicht nur Fundstellen in einem Text, sondern eine formale Sprache.
Formale Sprache
Ein Alphabet ist eine endliche Menge von Zeichen. Ein Wort ist eine endliche Folge dieser Zeichen. Eine Sprache ist eine Menge solcher Wörter.
Die Grundbausteine theoretischer regulärer Ausdrücke sind:
∅: die leere Sprache, die kein Wort enthältε: das leere Wort, also ein Wort der Länge null- ein Alphabetzeichen wie
a - Alternative beziehungsweise Vereinigung
- Konkatenation, also Aneinanderfügen
- Kleene-Stern
*, also beliebig viele Wiederholungen einschließlich null
Für die Alternative wird theoretisch je nach Notation | oder + verwendet. Das ist eine wichtige Verwechslungsgefahr: In vielen praktischen Regex-Dialekten bedeutet + stattdessen „mindestens eine Wiederholung“.
Über dem Alphabet {a,b} beschreibt (a|b)(a|b) genau die vier Wörter aa, ab, ba und bb.
(ab)* beschreibt ε, ab, abab, ababab und so weiter. Das leere Wort gehört dazu, weil der Block auch nullmal wiederholt werden darf.
Dagegen beschreibt a*|b* nur Wörter aus lauter a oder lauter b. Gemischte Wörter wie ab gehören nicht dazu.
Ein Ausdruck ist eine Beschreibung; seine Sprache ist die Menge aller Wörter, die diese Beschreibung erfüllt.
Vom Ausdruck zum endlichen Automaten
Ein endlicher Automat besitzt endlich viele Zustände. Er liest ein Wort Zeichen für Zeichen, wechselt dabei den Zustand und entscheidet am Ende, ob das Wort akzeptiert wird.
Theoretische reguläre Ausdrücke und endliche Automaten sind gleich mächtig: Zu jedem regulären Ausdruck gibt es einen endlichen Automaten mit derselben Sprache, und zu jedem endlichen Automaten gibt es einen passenden regulären Ausdruck.
Betrachte die Sprache aller Binärwörter, die auf 1 enden. Ein Ausdruck dafür ist (0|1)*1.
Ein deterministischer Automat benötigt dafür zwei Zustände:
| Aktueller Zustand | Eingabe 0 | Eingabe 1 |
|---|---|---|
q0: Start, nicht akzeptierend | q0 | q1 |
q1: akzeptierend | q0 | q1 |
Nach jeder gelesenen 1 steht der Automat in q1, nach jeder 0 in q0. Deshalb akzeptiert er genau die nichtleeren Wörter, deren letztes Zeichen 1 ist. 1, 01 und 101 werden akzeptiert; ε, 0 und 110 werden abgelehnt.
Für die systematische Umwandlung eines Ausdrucks in einen Automaten kann eine Konstruktion mit ε-Übergängen verwendet werden. In der Gegenrichtung lassen sich Zustände eliminieren oder Pfade schrittweise durch Ausdrücke beschreiben.
Regex zuverlässig entwerfen und testen
Praktische Regex-Dialekte teilen viele Grundideen, sind aber nicht vollständig einheitlich. Unterschiede betreffen unter anderem Zeichenklassen, Anker, Unicode, Zeilenmodi, Capturing, Look-behind und die Schreibweise von Ersetzungen.
Gehe deshalb in fünf Schritten vor:
- Formuliere genau, welche Zeichenketten passen sollen.
- Zerlege die Bedingung in feste Zeichen, Auswahl, Reihenfolge und Wiederholungen.
- Entscheide zwischen Teiltreffer und Ganzstring-Prüfung.
- Bilde das Muster und erkläre jeden Teil.
- Teste passende, unpassende und grenzwertige Eingaben im vorgesehenen Dialekt.
Gesucht sind Zahlen mit einer bis zehn Ziffern ohne führende Null.
Das Muster [1-9][0-9]{0,9} beginnt mit einer Ziffer von 1 bis 9. Danach folgen null bis neun weitere Ziffern.
Gute Testfälle sind:
- passend:
1,42,9876543210 - unpassend:
0,012,12345678901 - Grenzfälle: eine Ziffer und genau zehn Ziffern
Für eine Eingabeprüfung muss zusätzlich sichergestellt sein, dass nicht nur ein Teil der Eingabe getestet wird.
Komplexe Engine-Erweiterungen können über klassische reguläre Sprachen hinausgehen. Besonders Rückwärtsreferenzen vergleichen einen Treffer mit zuvor gespeichertem Text. Ein praktischer „Regex“ ist daher nicht immer ein regulärer Ausdruck im strengen theoretischen Sinn.
Ein gutes Muster ist nicht bloß möglichst kurz. Es muss die beabsichtigten Fälle ausreichend genau erfassen, verständlich bleiben und im verwendeten Regex-Dialekt zuverlässig funktionieren.
Karteikasten
Überlege zuerst selbst und drehe die Karte anschließend zum Prüfen um.
Alles auf einen Blick
- Regulärer Ausdruck
- Muster lesen: Literale und Metazeichen
- Zeichen auswählen: Zeichenklassen und Punkt
- Häufigkeit festlegen: Quantoren
- Struktur bilden: Gruppen und Alternativen
- Treffer begrenzen: Anker oder Ganzstring-Prüfung
- Verhalten prüfen: positive, negative und grenzwertige Fälle
- Theorie verstehen: Sprache und endlicher Automat
Abschluss-Check
Wenn du alle drei Antworten begründen kannst, kannst du Regex-Bausteine nicht nur erkennen, sondern zu einer gewünschten Zeichenmenge zusammensetzen und mit passenden Gegenbeispielen prüfen.
Mit Google fortfahren