Reguläre Ausdrücke: Der gierige Punkt, fehlende Anker und verschachtelte Wiederholung

Inhalt
Ein regulärer Ausdruck wird an dem Fall geprüft, für den er geschrieben wurde, er trifft, und er geht in Betrieb. Was er mit dem zweiten Fall macht, ist eine eigene Frage, und die Antwort lautet häufig: Er trifft ihn auch – bloß nicht die Stelle, die gemeint war.
Die drei folgenden Fehler überstehen jede Durchsicht, weil keiner von ihnen scheitert. Sie liefern etwas, das Etwas wirkt in der Stichprobe plausibel, und der Unterschied zeigt sich als leicht falsche Daten statt als Fehlermeldung.

Der Punkt ist gierig, und der Punkt ist kein Zeichen
.* nimmt alles, was es bekommen kann, und gibt nur zurück, was es zurückgeben muss. In einer Zeile mit zwei Verweisen beginnt href="(.*)" beim ersten href, läuft bis zum Zeilenende und zieht sich dann bis zum letzten erreichbaren Anführungszeichen zurück – Ergebnis ist ein Treffer, der beide Verweise und die Auszeichnung dazwischen enthält.
Zwei Dinge beheben das. Das faule Wiederholungszeichen .*? hält beim ersten Anführungszeichen, das den Rest des Musters aufgehen lässt. Die verneinte Klasse [^"]* kann ein Anführungszeichen gar nicht erst überschreiten, sagt also dasselbe ohne jeden Rückzieher – und das ist die Fassung, die zu schreiben ist, weil sie die Bedingung ausspricht, statt sich darauf zu verlassen, wie sich die Maschine zurückarbeitet.
Eine verneinte Klasse schließt den Zeilenumbruch ein
Der Punkt trifft keinen Zeilenumbruch, solange der Schalter s nicht gesetzt ist. Eine verneinte Zeichenklasse trifft ihn – [^&] heißt alles, was kein Und-Zeichen ist, und ein Zeilenumbruch ist kein Und-Zeichen.
Text utm_source=newsletter
utm_medium=email
^utm_([a-z_]+)=([^&]+)$ mit Schalter m: 2 Treffer
^utm_([a-z_]+)=([^&]+) ohne ihn: 1 Treffer über beide Zeilen
^utm_([a-z_]+)=([^&\s]+) die Behebung: Leerraum mit ausgeschlossen
Das ist der Fehler, der wie ein Datenproblem aussieht. Ein Muster, das Parameter aus einer mehrzeiligen Eingabe zieht, liefert einen Wert, der zufällig alles Nachfolgende enthält, der Wert wird in ein Feld geschrieben, und das Feld sieht aus wie ein sehr langer Kampagnenname und nicht wie ein Fehler.
Anker sagen wo, nicht ob
Ohne Anker trifft ein Muster irgendwo in der Eingabe, was zum Herausziehen meist erwünscht und zum Prüfen fast nie erwünscht ist. Eine Prüfung, ob ein Feld nur Ziffern enthält, geht mit [0-9]+ auch für abc123def durch, denn nach dem Rest wurde das Muster nie gefragt.
Prüfen braucht ^ und $ an beiden Enden, und es braucht das Wissen, was die beiden in der verwendeten Spielart bedeuten: ohne den Mehrzeilenschalter den Anfang und das Ende der gesamten Eingabe, mit ihm jeder Zeile. Was davon richtig ist, hängt ganz daran, ob die Eingabe ein Wert oder eine Liste von Werten ist – eine Frage, die eine ausdrückliche Antwort verdient statt der Voreinstellung, die die Bibliothek mitbrachte.
Verschachtelte Wiederholung ist ein Problem anderer Art
Die drei Fehler oben liefern die falsche Antwort. Dieser liefert gar keine. Enthält eine wiederholte Gruppe etwas, das selbst wiederholbar ist – (a+)+, (\s*\w+)*, (.*,)* -, gibt es exponentiell viele Arten, die Eingabe auf die Wiederholungen zu verteilen, und die Maschine probiert sie alle, bevor sie feststellt, dass es keinen Treffer gibt.
| Muster | Gegen eine nicht passende Eingabe der Länge n |
|---|---|
(a+)+$ |
exponentiell – dreißig Zeichen sind bereits Sekunden |
(\s*\w+)*$ |
dieselbe Gestalt, versteckt hinter zwei harmlos wirkenden Klassen |
^(\w+\s?)+$ |
ein verbreitetes Muster zur Namensprüfung und eine Betriebsstörung |
a+$ |
linear – die äußere Wiederholung war das ganze Problem |
Die gefährliche Eigenschaft ist, dass diese Muster bei jeder passenden Eingabe schnell sind. Die Explosion tritt nur bei Eingaben ein, die nicht passen – ein Prüfmuster verhält sich also jahrelang einwandfrei, trifft dann auf eine einzige fehlerhafte Einsendung und belegt einen Arbeitsprozess, bis jemand ihn abschießt.
Die Regel dagegen ist mechanisch: kein Wiederholungszeichen unmittelbar um eine Gruppe, deren Inhalt selbst wiederholt wird. Wo sich das nicht vermeiden lässt, drückt eine verneinte Klasse meist dieselbe Absicht aus – [^,]+, statt (.*,) – und nimmt die Mehrdeutigkeit weg, die der Rückzieher durchprobiert hat.
Was zu prüfen ist, bevor ein Muster Vertrauen verdient
Drei Eingaben beantworten das meiste. Der Fall, für den es geschrieben wurde, zur Bestätigung, dass es trifft. Ein Fall mit zwei Vorkommen – dort zeigt sich die Gier, und mit einem einzigen Beispiel zeigt sie sich nie. Und ein Fall, der nicht treffen darf; dort verraten sich Anker und verschachtelte Wiederholung gleichermaßen, der eine dadurch, dass er trotzdem trifft, die andere dadurch, dass sie nicht fertig wird.
Der dritte ist der, der ausgelassen wird, und er ist der, der beide Probleme fängt, die sich dem Muster nicht ansehen lassen. Eine Prüfsammlung für einen regulären Ausdruck ist drei Zeilen lang, und sie ist der Unterschied zwischen einem Ausdruck, der funktioniert, und einem, dem noch niemand widersprochen hat.