Der Regex ist fertig, und die Hälfte der Testfälle trifft, der Rest nicht. Teuer ist nie das Schreiben, sondern das Herausfinden, warum. Die drei folgenden Fallen decken die meisten Fälle ab, jede mit einer festen Prüfreihenfolge.
Zwei Arten von Fehlschlag unterscheiden
Kein Treffer und Treffer mit falschem Inhalt sind verschiedene Probleme. Das erste deutet meist auf eine falsche Zeichenklasse oder ein falsches Flag, das zweite fast immer auf gierige Quantoren und die Position der Klammern. Die Einordnung spart die halbe Arbeit: zuerst prüfen, ob überhaupt getroffen wird, dann, was Gruppe 1 enthält.
Falle 1: Ein gieriger Quantor frisst den Rest
.* ist standardmäßig gierig: Er läuft bis zum Zeilenende und springt dann zurück. title="(.*)" auf title="a" id="b" liefert daher a" id="b statt a.
Zwei Auswege: den Quantor faul machen (.*?) oder eine präzise Zeichenklasse nutzen ([^"]*). Die zweite Variante ist meist schneller und stabiler – faule Quantoren springen weiterhin zurück, Zeichenklassen nicht.
Falle 2: Eine Escaping-Ebene zu viel (oder zu wenig)
Steht ein Regex in einem String-Literal, laufen Backslashes durch zwei Parser. In JavaScript schreiben Sie \\d, um ein Regex-\d zu erhalten; kopieren Sie \\\\d von woanders, passt das Muster auf einen echten Backslash plus d. Dasselbe gilt für \s, \. und \/.
Schnelltest: Lassen Sie sich den endgültigen Pattern-String im Debugger ausgeben und vergleichen Sie ihn mit Ihrer Annahme. Das löst einen großen Teil der Fälle „ich habe es doch geschrieben, aber nichts trifft".
Falle 3: Die Flags m und g
Ohne m treffen ^ und $ nur Anfang und Ende der gesamten Zeichenkette; zeilenweises Prüfen in mehrzeiligem Text scheitert. Mit m respektieren sie jede Zeilengrenze.
Mit g merkt sich das Regex-Objekt die Position des letzten Treffers (lastIndex). Wird dasselbe globale Regex in einer Schleife wiederverwendet, setzt der zweite Aufruf dort an – das wirkt wie ein übersprungener Treffer. Pro Durchlauf eine neue Instanz erzeugen oder lastIndex auf null setzen.
Ablauf in vier Schritten
- Eingabe verkleinern: Teststring auf die kürzeste reproduzierende Variante reduzieren
- Muster halbieren: an
|teilen oder optionale Teile löschen, bis der fehlerhafte Abschnitt sichtbar wird - Gruppen prüfen: nachsehen, was jede Gruppe tatsächlich enthält
- Andere Eingaben testen: je eine, die treffen soll, und eine, die nicht treffen darf
Schritt vier wird am häufigsten ausgelassen. Ein Treffer beweist nicht, dass das Muster anderes ablehnt – Über-Treffer richten oft größeren Schaden an, etwa wenn statt reinem Text ein ganzes HTML-Fragment ersetzt wird.
Noch ein Wort zur Performance
Verschachtelte Quantoren wie (a+)+$ lösen bei langen, nicht passenden Eingaben katastrophales Backtracking aus und können den Browser sekundenlang blockieren. Der Test ist einfach: Eingabelänge verdoppeln und prüfen, ob die Laufzeit mehr als viermal steigt. Wenn ja, solche Muster nicht direkt auf Nutzereingaben anwenden.
In einem Satz
Erst klären, ob kein Treffer oder falscher Inhalt, dann Gier, Escaping und Flags in dieser Reihenfolge prüfen. Das ersetzt die meisten Vermutungen.
Die drei Zahlen, die Sie zuerst lesen
Wenn Sie einen Regex-Tester öffnen, ignorieren Sie kurz die hübsche Hervorhebung und sehen Sie zuerst auf diese drei Dinge:
- Die Gesamtzahl der Treffer. Null heißt „gar nichts passt" — ein Problem mit Zeichenklasse oder Flag. Mehr als null, aber weniger als erwartet, bedeutet meist ein fehlendes
g-Flag oder einen Teil des Musters, der alles danach verschluckt. - Start- und Endposition jedes Treffers. Positionen erklären mehr als Inhalte: Reicht der erste Treffer bis zum Textende, ist ein gieriger Quantor am Werk.
- Was Gruppe 1 tatsächlich erfasst hat. Die Gruppe isoliert zu betrachten trennt sofort „hat nicht gepasst" von „hat gepasst, aber das Falsche erfasst".
Die Reihenfolge zählt: erst Anzahl, dann Position, dann Gruppen. Andersherum ziehen die farbigen Hervorhebungen den Blick mit, bis alles falsch aussieht.
Drei blinde Flecken bei CJK und Unicode
w ist die Kurzform für [A-Za-z0-9_] und enthält keinerlei CJK-Zeichen. w+ gegen „张三" liefert also nichts. Für chinesischen Text nehmen Sie [一-龥] oder den weiteren Bereich [一-鿿].
. passt ohne das s-Flag nicht auf einen Zeilenumbruch. Bei mehrzeiligem Text endet .* am Ende der ersten Zeile. Entweder [sS]* verwenden oder s einschalten.
-Wortgrenzen sind bei Chinesisch weitgehend nutzlos, weil chinesische Wörter nicht durch Leerzeichen getrennt sind und es keine Grenze zu finden gibt. Wortsegmentierung braucht eine eigene Bibliothek, keinen Regex.
Noch etwas: Chinesische Satzzeichen sind Vollbreite. , und , sind verschiedene Codepunkte, ein Formular auf Halbbreite-Komma weist daher jeden zurück, der ein Vollbreite-Komma tippt.
Das Muster mit einer Falltabelle festnageln
„Beim Testen lief es" heißt nicht, dass der Regex korrekt ist. Verlässlich ist eine kleine Tabelle mit drei bis fünf Fällen pro Muster:
- Muss passen: eine normale Eingabe plus die Randfälle — kürzeste, längste, exakt auf der Grenze.
- Darf nicht passen: der leere String, nur Leerraum, und unsaubere Daten mit überzähligen Prä- oder Suffixen.
- Neigt zum Überpassen: fast passende Eingaben anderer Klasse — bei einer Telefonnummer eine mit Präfix oder eine Festnetznummer, die mit 1 beginnt.
Die Tabelle zahlt sich später aus: Wenn jemand das Muster ein halbes Jahr später ändert, zeigt ein Lauf der Fälle sofort, ob bisheriges Verhalten kaputtging. Ohne Tabelle ist jede Änderung blind.
Wo ein Regex nichts zu suchen hat
Regexes sind kein Allzweckwerkzeug, an manchen Stellen scheitern sie zwangsläufig:
- Verschachteltes HTML oder XML parsen. Tags verschachteln sich beliebig, Regexes können nicht rekursiv arbeiten.
<div>.*?</div>endet immer am ersten schließenden Tag und erfasst die äußere Struktur falsch. Nehmen Sie einen DOM-Parser. - JSON parsen. Strings dürfen beliebige Escapes und Klammern enthalten, ein Regex deutet sie falsch. Nehmen Sie
JSON.parse. - E-Mail-Adressen vollständig validieren. RFC 5322 erlaubt eine enorme Vielfalt; 100 Prozent Genauigkeit ist schwer zu schreiben und zu pflegen. Praktisch: Länge begrenzen, genau ein
@und mindestens ein Punkt verlangen, dann eine Bestätigungsmail schicken. - Sehr lange Eingaben. Ein Muster mit verschachtelten Quantoren backtrackt bei Zehntausenden nicht passenden Zeichen exponentiell und friert den Browser ein. Begrenzen Sie zuerst die Länge.
Der Test ist einfach: Erlaubt die Zielstruktur beliebige Verschachtelung oder Rekursion? Wenn ja, kein Regex.