
„Greedy“ vs. „Lazy“ bei der Regex-Matching: Warum Ihr Muster zu viel erfasst
Veröffentlicht am 24. Juli 2026
Man schreibt <b>.*</b>, um den Inhalt eines Fettdruck-Tags zu extrahieren, testet es mit <b>Hello</b> – es funktioniert einwandfrei. Dann wenden Sie es auf echtes HTML mit zwei Fettdruck-Tags in derselben Zeile an – <b>Hello</b> and <b>World</b> – und statt zweier Treffer erhältst du einen einzigen riesigen Treffer, der sich über beide Tags erstreckt. Das ist kein Fehler in Ihrer Regex-Engine; es ist das Standardverhalten von *, + und {n,m}, und es lässt sich mit einem einzigen Zeichen beheben, sobald man weiß, was hier vor sich geht.
Warum .* mehr erfasst, als Sie erwarten
Standardmäßig sind Quantoren in regulären Ausdrücken gierig – .* bedeutet nicht „einige Zeichen abgleichen“, sondern „so viele Zeichen wie möglich abgleichen und erst dann zurückgehen, wenn der Rest des Musters dies unbedingt erfordert“.
Gehen wir <b>.*</b> im Vergleich zu <b>Hello</b> and <b>World</b> Schritt für Schritt durch:
<b>passt auf das erste<b>..*beginnt damit, den gesamten Rest der Zeichenkette zu verarbeiten – alles bis zum Ende, einschließlich des zweiten<b>World</b>.- Die Engine muss dann
</b>finden, um den Abgleich abzuschließen, und beginnt daher, sich vom Ende von.*aus Zeichen für Zeichen zurückzuziehen. - Die erste Stelle (rückwärts vom Ende aus betrachtet), an der
</b>passt, ist das allerletzte</b>in der Zeichenkette – nicht das erste, bei dem sie „logischerweise“ anhalten sollte.
Somit ergibt sich als Übereinstimmung letztendlich <b>Hello</b> and <b>World</b> in seiner Gesamtheit, da das gierige Abgleichen immer zuerst die längstmögliche Zeichenkette versucht und diese nur so wenig wie nötig verkürzt, damit der Rest des Musters erfolgreich abgeglichen werden kann.
Die Lösung: Den Quantor mit ? „lazy“ machen
Das Hinzufügen eines ? unmittelbar nach einem Quantor wandelt diesen von „greedy“ in „lazy“ um (auch als „non-greedy“ oder „reluctant“ bezeichnet): *?, +?, ??, {n,m}?.
Ein „lazy“-Quantifier verhält sich umgekehrt: Er beginnt damit, so wenige Zeichen wie möglich abzugleichen, und erweitert sich erst dann, wenn der Rest des Musters noch nicht erfolgreich abgeglichen werden kann.
<b>.*?</b> gegen dieselbe Zeichenfolge:
<b>passt auf das erste<b>..*?passt zunächst auf null Zeichen.- Die Engine prüft: Passt
</b>genau an dieser Stelle? Nein (wir befinden uns bei „Hello…“, noch nicht bei einem</b>) – also erweitert sie.*?um genau ein Zeichen und prüft erneut. - Dies wiederholt sich Zeichen für Zeichen, bis
.*?genauHelloverbraucht hat; an diesem Punkt passt</b>sofort.
Ergebnis: <b>Hello</b> und <b>World</b> werden als zwei separate Übereinstimmungen zurückgegeben, was fast immer genau das ist, was man beim Parsen von tag- oder trennzeichenähnlichen Strukturen eigentlich beabsichtigt hat.
Wenn Sie tatsächlich „greedy“ wollen (es ist nicht einfach nur „die falsche Standardeinstellung“)
„Greedy“ ist kein Fehler in der Sprache – es ist korrekt für einen anderen, ebenso häufigen Fall: das Abgleichen der äußersten Grenze von etwas, nicht der kleinsten Einheit darin. Wenn Sie „alles zwischen dem ersten { und dem letzten } “ aus einem Klumpen JSON-ähnlichen Textes extrahieren (etwa, um ein ganzes Objekt unabhängig von der Verschachtelung zu erfassen), ist „greedy“ genau richtig, während „lazy“ stattdessen beim ersten inneren } aufhören würde, was zu einem abgeschnittenen, ungültigen Fragment führen würde.
Die Faustregel: „lazy“ für wiederholte kleine, abgegrenzte Blöcke (Tags, Zeichenfolgen in Anführungszeichen, Listenelemente); „greedy“ für „den gesamten äußeren Bereich erfassen“.
Kurzübersicht
| Muster | Verhalten | Verwenden Sie es, wenn |
|---|---|---|
.*, .+, {n,m} |
„Greedy“ – findet die längste mögliche Übereinstimmung | Sie den äußersten Bereich wollen oder es nur eine Übereinstimmung in der Zeichenfolge gibt |
.*?, .+?, {n,m}? |
Lazy – findet die kürzestmögliche Übereinstimmung | Sie haben mehrere ähnliche, durch Trennzeichen getrennte Abschnitte und möchten jeden einzeln |
Wenn Sie sich nicht sicher sind, wie sich ein Muster bei Ihrer tatsächlichen Eingabe – und nicht nur bei Ihrer Testzeichenfolge – verhält, können Sie es im tatsächlichen Text mit mehreren Übereinstimmungen in einem Regex-Tester mit Live-Hervorhebung der Übereinstimmungen ausführen – der Unterschied wird sofort sichtbar: bei „greedy“ sehen Sie einen riesigen hervorgehobenen Block, bei „lazy“ hingegen mehrere separate Blöcke, was in der Regel schneller ist, als die Zeichen einzeln durchzugehen.