Eine Syntax-Tabelle, kein Tutorial
Reguläre Ausdrücke sind von Natur aus dicht. Ein Muster wie ^(?:\d{1,3}\.){3}\d{1,3}$ packt einen ganzen IPv4-Validator in dreißig Zeichen, was wunderbar ist, wenn du es geschrieben hast, und elend, wenn du den Ausdruck von jemand anderem liest. Der Großteil der Schwierigkeit ist nicht konzeptuell – es ist, dass der Wortschatz groß, knapp und leicht nur halb erinnert ist.
Diese Seite ist eine Nachschlagetabelle für diesen Wortschatz, geordnet so, wie Muster tatsächlich gebaut werden: was ein einzelnes Zeichen matcht, wie du deine eigenen Zeichensätze definierst, wie du „wiederhole das" sagst, wo du den Match verankerst, wie du gruppierst und alternierst, und welche Flags das Verhalten der Engine ändern. Der Filter durchsucht Tokens, Beschreibungen und Beispiele auf einmal, sodass das Tippen von „lazy", „boundary" oder „lookbehind" direkt zur Zeile springt, an die du dich nur halb erinnerst.
Welchem Geschmack diese Tokens folgen
Reguläre Ausdrücke sind nicht eine Sprache. Grep, PCRE, Python, Java, Go's RE2 und JavaScript teilen sich einen gemeinsamen Kern, stimmen aber an den Rändern nicht überein. Alles hier zielt auf den JavaScript-Geschmack ab, der von ECMAScript definiert wird, weil das im Browser, in Node.js und in den meisten Frontend-Werkzeugen läuft.
Drei Unterschiede sind erwähnenswert. Erstens: Lookbehind – (?<=...) und (?<!...) – wird in modernen JavaScript-Engines unterstützt, fehlt aber in Go's RE2 und in älteren Safari-Versionen, sodass Muster, die darauf beruhen, nicht überall portabel sind. Zweitens: JavaScript hat kein x-Verbose-Flag, sodass du ein Muster nicht wie in Python über mehrere Zeilen mit Kommentaren verteilen kannst; lange Muster werden meist aus String-Fragmenten zusammengesetzt. Drittens: \d und \w sind in JavaScript standardmäßig nur ASCII; \w matcht also keine akzentuierten Buchstaben oder CJK-Zeichen, es sei denn, du wechselst zu Unicode-Eigenschafts-Escapes wie \p{L} mit dem u-Flag.
Muster schreiben, die wartbar bleiben
Zwei Gewohnheiten verhindern die meisten Regex-Probleme. Die erste ist, bewusst zu verankern. Ein nicht verankertes Muster sucht an beliebiger Stelle im String nach einem Match, was du beim Scannen willst und fast nie beim Validieren. Das Hinzufügen von ^ und $ verwandelt „enthält etwas, das wie ein Datum aussieht" in „ist ein Datum", und genau dieser Unterschied steckt hinter einem überraschend großen Anteil an Validierungsfehlern.
Die zweite ist, Faulheit und negierte Zeichensätze gegen gierige Wildcards zu bevorzugen. Der klassische Fehler ist <.+> auf HTML-ähnlichem Text: Weil + gierig ist, verschluckt es alles bis zum letzten > in der Zeile. <.+?> oder, besser, <[^>]+> matcht ein einzelnes Tag. Die negierte-Klasse-Version ist auch deutlich schneller, weil die Engine nie zurückverfolgen muss.
Schließlich solltest du dir katastrophales Backtracking bewusst sein. Verschachtelte Quantoren, wie in (a+)+b, können die Engine exponentiell viele Möglichkeiten ausprobieren lassen, bevor sie schließt, dass es keinen Match gibt, was einen Validierungsaufruf zu einem Denial-of-Service-Vektor macht, sobald das Muster auf Nutzereingaben trifft. Wenn ein Muster eine quantifizierte Gruppe enthält, die selbst einen Quantor enthält, schreibe es um – meist leistet eine einzelne Zeichenklasse mit einem Quantor denselben Job in linearer Zeit. Und wenn ein Muster länger als eine oder zwei Zeilen wird, ist die ehrliche Antwort oft, dass ein echter Parser das richtige Werkzeug ist und der Regex nicht.