Skip to content
Back to Blog
developerregex-testerregexweb-development

Regex Lookahead und Lookbehind einfach erklärt mit Beispielen

Lookahead und Lookbehind sind die Regex-Funktionen, die Leute kopieren, aber nie verstehen. Hier werden sie mit echten Beispielen erklärt, die du live in verschiedenen Sprachen testen kannst.

SZ
Founder, Molixa
11 min read
Teilen
Regex Lookahead und Lookbehind einfach erklärt mit Beispielen
Table of contents9 sections

Regex-Lookahead und -Lookbehind sind Null-Längen-Assertionen: Sie prüfen, ob ein Muster neben Ihrer Übereinstimmung erscheint oder nicht, ohne Zeichen zu verbrauchen oder in das Ergebnis aufzunehmen. Lookahead (?=...) prüft, was folgt, Lookbehind (?<=...) prüft, was vorausgeht, und beide haben negative Formen für "nicht gefolgt von" und "nicht vorausgegangen von".

Das Wort "Null-Länge" ist der Teil, der jeden verwirrt. Ein normales Regex-Token matcht ein Zeichen und bewegt den Cursor vorwärts. Eine Assertion matcht eine Position. Sie betrachtet den umgebenden Text, gibt wahr oder falsch zurück und lässt den Cursor genau dort, wo er war. Deshalb können Sie mehrere Lookaheads an derselben Stelle stapeln, was der Trick hinter fast jedem Passwort-Validierungsmuster ist, das Sie jemals eingefügt haben.

Die vier Lookaround-Assertions#

Es gibt genau vier Lookarounds, die sich sauber entlang zweier Achsen aufteilen: Richtung (voraus oder zurück) und Polarität (positiv oder negativ). Sobald man sie in einer Tabelle sieht, wirkt die Syntax nicht mehr willkürlich.

AssertionSyntaxBedeutungEinfaches Deutsch
Positiver Lookahead(?=...)Der Treffer muss von ... gefolgt sein"wird gefolgt von"
Negativer Lookahead(?!...)Der Treffer darf nicht von ... gefolgt sein"wird nicht gefolgt von"
Positiver Lookbehind(?<=...)Dem Treffer muss ... vorausgehen"steht nach"
Negativer Lookbehind(?<!...)Dem Treffer darf kein ... vorausgehen"steht nicht nach"

Die Punkte innerhalb jeder Assertion sind ein normales Untermuster. Sie werden ausgewertet, die Engine merkt sich, ob sie übereinstimmten, und verwirft dann die Cursorbewegung. Nichts innerhalb eines Lookarounds landet in Ihrem Treffer oder Ihren Erfassungsgruppen.

Tipp: Wenn Sie jemals bestätigen möchten, dass eine Assertion wirklich null breit ist, sehen Sie sich die Länge des übereinstimmenden Textes an. Ein Muster, das nur aus Lookarounds besteht, stimmt mit einer leeren Zeichenkette an einer Position überein. Die interessante Ausgabe ist wo es übereinstimmte, nicht was.

Positive Lookahead: Etwas finden, dem etwas anderes folgt#

Angenommen, Sie haben Preise wie 42USD, 99EUR und 7GBP und möchten nur die Zahl, der unmittelbar USD folgt, ohne die Währungsbezeichnung selbst zu erfassen.

\d+(?=USD)

Bei 42USD 99EUR 7USD werden 42 und 7 gefunden. Das USD ist für die Übereinstimmung erforderlich, wird aber nie erfasst, sodass Sie saubere Zahlen erhalten, die Sie direkt verarbeiten können. Vergleichen Sie das mit \d+USD, das Sie zwingt, das USD nachträglich zu entfernen.

Das ist der gesamte Nutzen von Lookahead: eine Bedingung, die die Übereinstimmung steuert, ohne Teil davon zu werden.

Negative Lookahead: Übereinstimmung, wenn nicht gefolgt von#

Kehren Sie die Behauptung zu (?!...) um und Sie erhalten "Übereinstimmung mit einem Element, dem nicht ein anderes Element folgt." Ein klassischer Fall ist die Übereinstimmung mit einem Wort, dem kein bestimmtes Suffix folgt.

\bcat(?!alog)\b

Gegen cat catalog category cats stimmt dies mit dem eigenständigen cat und dem cat in cats überein (weil cats nicht catalog ist), überspringt aber catalog. Die \b-Wortgrenzen verhindern, dass es das cat in nicht zusammenhängendem Text findet.

Negative Lookahead ermöglicht auch Muster wie "Übereinstimmung mit einer Zeile, die X nicht enthält", wenn Sie es verankern:

^(?!.*ERROR).*$

Dies stimmt mit jeder vollständigen Zeile überein, die das Wort ERROR nirgendwo enthält. Der Lookahead scannt zuerst die gesamte Zeile; wenn er ERROR findet, schlägt die Behauptung fehl und die Zeile wird übersprungen. Dies ist wirklich nützlich zum Filtern von Logs.

Lookbehind: Prüfen, was davor steht#

Lookbehind erledigt die gleiche Aufgabe in die andere Richtung. Positive Lookbehind (?<=...) erfordert ein vorhergehendes Muster; negative Lookbehind (?<!...) verbietet eines.

Ein häufiger Fall ist das Extrahieren eines Betrags, der einem Währungssymbol folgt, ohne das Symbol zu erfassen:

(?<=\$)\d+(\.\d{2})?

Bei Preis: 42,50 € und kostenlos würde dies 42,50 matchen und das aus dem Ergebnis ausschließen. Negative Lookbehind ist ebenso nützlich. Um eine Zahl zu matchen, der kein Dollarzeichen vorausgeht:

(?<!\$)\b\d+\b

Dies matcht lose Zahlen wie 2024, während monetäre $99-Werte ignoriert werden. Lookbehind ist der Punkt, an dem Unterschiede zwischen den Regex-Engines spürbar werden, was das Nächste ist, was Sie wissen müssen, bevor Sie ein Muster ausliefern.

Die Portabilitätsfalle: Lookbehind ist nicht universell#

Dieser Teil wird in den meisten Tutorials ausgelassen, und genau dieser Teil bringt Produktionscode zum Scheitern. Lookahead wird fast überall unterstützt. Lookbehind nicht, und selbst wo es existiert, unterscheiden sich die Regeln, ob es variable Längen haben darf, je nach Engine.

Engine / VarianteLookaheadLookbehindVariables Lookbehind
JavaScript (ES2018+)JaJaJa
PCRE / PCRE2 (PHP, viele Tools)JaJaNein (nur feste Länge)
Python (re)JaJaNein (nur feste Länge)
Python (regex-Modul)JaJaJa
Go (regexp, RE2)NeinNeinNein

Zwei Dinge fallen sofort auf. Erstens verwendet Gos Standardpaket regexp die RE2-Engine, die bewusst überhaupt kein Lookaround hat, weil RE2 eine lineare Laufzeit garantiert und Lookarounds diese Garantie brechen. Wenn Sie (?<=\$) in Go schreiben, wird es nicht kompiliert. Sie müssen stattdessen mit Erfassungsgruppen umstrukturieren.

Zweitens bedeutet "Lookbehind mit fester Länge", dass PCRE und Pythons eingebautes re ein Lookbehind ablehnen, dessen Breite variieren kann. (?<=cat|dog) funktioniert, weil beide Alternativen 3 Zeichen lang sind; (?<=cats?) schlägt in diesen Engines fehl, weil der Treffer 3 oder 4 Zeichen breit sein könnte. JavaScript und Pythons Drittanbieter-Modul regex erlauben beide variables Lookbehind, sodass dasselbe Muster, das in Ihrer Browserkonsole funktioniert, in einem Python-Backend einen Fehler auslösen kann.

Warnung: "Funktioniert auf regex101" ist nicht dasselbe wie "funktioniert in meiner Sprache." regex101 lässt Sie eine Variante auswählen, aber es ist leicht, unter PCRE zu testen und dann an einen Go- oder Python-Dienst zu liefern, der das Muster ablehnt. Bestätigen Sie immer gegen Ihre tatsächliche Ziel-Engine.

Ein realer Anwendungsfall: Passwortrichtlinien validieren#

Der häufigste Ort, an dem Entwickler auf Lookahead stoßen, sind Passwortregeln. Es ist das klarste Beispiel für das Stapeln von Null-Breite-Assertions. Angenommen, Ihre Richtlinie lautet: mindestens 8 Zeichen, mit mindestens einem Kleinbuchstaben, einem Großbuchstaben und einer Ziffer.

^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$

Gehen wir von links nach rechts durch:

  • ^ verankert am Anfang der Zeichenkette.
  • (?=.*[a-z]) stellt sicher, dass irgendwo voraus ein Kleinbuchstabe vorkommt. Der Cursor bewegt sich nicht.
  • (?=.*[A-Z]) stellt sicher, dass ein Großbuchstabe existiert, wieder vom Start aus.
  • (?=.*\d) stellt sicher, dass eine Ziffer existiert.
  • .{8,}$ verbraucht schließlich 8 oder mehr Zeichen bis zum Ende.

Jeder Lookahead scannt unabhängig die gesamte Zeichenkette von derselben Startposition, da keiner den Cursor bewegt. Genau deshalb können Sie „muss alle diese in beliebiger Reihenfolge enthalten“ als flache Liste von Assertions ausdrücken. Ohne Lookahead bräuchten Sie eine hässliche Alternation, die jede mögliche Reihenfolge abdeckt.

Um Leerzeichen zu verbieten, fügen Sie einen negativen Lookahead hinzu: (?!.*\s). Um ein Sonderzeichen zu verlangen, fügen Sie (?=.*[!@#$%^&*]) hinzu. Das Muster wächst um eine Assertion pro Regel, was weitaus lesbarer ist als die Alternative.

Schritt 1: Bauen Sie die Assertions eine Regel nach der anderen auf#

Beginnen Sie mit den Verankerungen und der Länge, fügen Sie dann einen einzelnen Lookahead hinzu und bestätigen Sie sein Verhalten, bevor Sie den nächsten hinzufügen. Fügen Sie das partielle Muster in einen kostenlosen Regex-Tester ein und testen Sie eine Zeichenkette, die bestehen sollte, und eine, die fehlschlagen sollte. Wenn Sie alle vier Assertions auf einmal hinzufügen und es sich falsch verhält, wissen Sie nicht, welche falsch ist.

Schritt 2: Testen Sie die Grenzfälle, nicht nur den glücklichen Pfad#

Ein Passwort-Regex, der Abcdef12 akzeptiert, ist nicht als korrekt bewiesen. Testen Sie die Zeichenketten, die fehlschlagen sollten: eine reine Kleinbuchstaben-Zeichenkette, eine ohne Ziffer, eine mit genau 7 Zeichen. Bestätigen Sie, dass jede aus dem richtigen Grund abgelehnt wird. Die Live-Hervorhebung in einem Tester zeigt Ihnen, ob ein Fehler von der Länge oder einer fehlenden Assertion stammt.

Schritt 3: Fixieren Sie die Engine, bevor Sie das Muster kopieren#

Sobald es funktioniert, stellen Sie den Tester auf die Engine ein, in der Sie es tatsächlich ausführen werden (JavaScript, PCRE, Python oder Go) und führen Sie dieselben Fälle erneut aus. Wenn Sie einen Lookbehind mit variabler Länge oder überhaupt ein Lookaround in Go verwendet haben, werden Sie es hier im Editor abfangen, nicht in einem fehlschlagenden CI-Build.

Lookahead vs. Capture Groups: Wann verwendet man was?#

Eine häufige Verwirrung ist, wann man einen Lookahead und wann eine einfache Capture Group verwenden sollte, da beide es ermöglichen, "X in der Nähe von Y" zu finden. Der Unterschied liegt darin, was im Treffer enthalten ist.

  • Verwenden Sie eine Capture Group (...), wenn Sie den umgebenden Text behalten und einen Teil daraus extrahieren möchten. Der gesamte Treffer enthält alles; die Gruppe isoliert einen Teil.
  • Verwenden Sie einen Lookaround, wenn der umgebende Text nur eine Bedingung ist und Sie ihn nicht im Ergebnis haben möchten. Der Treffer ist nur das Ziel.

Konkret: (\d+)USD findet 42USD und erfasst 42 in Gruppe 1. \d+(?=USD) findet nur 42 und erfasst nichts. Beide liefern 42, aber der erste behält USD im gesamten Treffer, der zweite nicht. Wenn Sie eine Suchen-und-Ersetzen-Aktion durchführen und USD unberührt lassen möchten, ist der Lookahead sauberer, da nichts wiederhergestellt werden muss.

Für tiefergehende Musterarbeit behandelt unser Leitfaden, wie Sie reguläre Ausdrücke mit einem Live-Regex-Tester meistern, Gruppen, Anker und Flags zusammen mit Lookarounds.

Kurzreferenz Spickzettel#

Halten Sie dies neben Ihrem Editor bereit:

  • (?=foo) Position, auf die foo folgt
  • (?!foo) Position, auf die nicht foo folgt
  • (?<=foo) Position, der foo vorausgeht
  • (?<!foo) Position, der nicht foo vorausgeht
  • Lookaheads sind nullbreit: sie behaupten, verbrauchen nie.
  • Stapeln Sie Lookaheads bei ^, um mehrere Bedingungen in beliebiger Reihenfolge zu erzwingen.
  • Lookbehind wird in Go (RE2) nicht unterstützt und muss in PCRE und Pythons integriertem re eine feste Länge haben.

Wenn Sie ein Muster validieren oder entwirren müssen, fügen Sie es in den Molixa Regex-Tester ein und beobachten Sie die Übereinstimmungen und Gruppen live, wechseln Sie dann die Varianten, um die Portierung zu bestätigen. Wenn Sie auch API-Payloads bearbeiten, passt der JSON-Formatter gut dazu, um Antworten zu bereinigen, bevor Sie sie mit Regex bearbeiten. Und falls Sie regex101 verwendet haben, erklärt unser kostenloser regex101-Alternativtest die Unterschiede.

Häufig gestellte Fragen#

Was ist der Unterschied zwischen Lookahead und Lookbehind in Regex? Lookahead (?=...) prüft den Text, der auf die aktuelle Position folgt, während Lookbehind (?<=...) den Text prüft, der ihr vorausgeht. Beide sind Null-Längen-Assertionen, die eine Bedingung testen, ohne den umgebenden Text in den Treffer einzubeziehen. Jede hat auch eine negative Form, (?!...) und (?<!...), für "nicht gefolgt von" und "nicht vorausgegangen von".

Unterstützt JavaScript Regex Lookbehind? Ja. JavaScript unterstützt sowohl Lookbehind als auch Lookbehind mit variabler Länge seit ES2018, daher funktioniert (?<=\$)\d+ in modernen Browsern und Node. Ältere Laufzeitumgebungen vor ES2018 tun dies nicht. Wenn Sie eine Legacy-Umgebung anvisieren, testen Sie dort oder strukturieren Sie mit einer Erfassungsgruppe anstelle eines Lookbehinds um.

Warum funktioniert mein Lookbehind in JavaScript, schlägt aber in Python fehl? Höchstwahrscheinlich liegt es an variabler Länge. Pythons integriertes re-Modul erlaubt nur Lookbehind mit fester Länge, daher schlägt (?<=cats?) fehl, weil die Breite variiert. JavaScript erlaubt Lookbehind mit variabler Länge, daher funktioniert dasselbe Muster dort. Verwenden Sie das Drittanbieter-Modul regex in Python für variable Längen oder schreiben Sie die Assertion auf eine feste Breite um.

Wie verwende ich Lookahead für die Passwortvalidierung? Stapeln Sie am Anfang des Musters einen positiven Lookahead pro Regel und konsumieren Sie dann die Zeichen. Beispiel: ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$ erfordert einen Kleinbuchstaben, einen Großbuchstaben, eine Ziffer und eine Mindestlänge von 8. Da Lookaheads Null-Längen-Assertionen sind, scannt jeder unabhängig die gesamte Zeichenkette von derselben Position aus.

Unterstützt Go Regex Lookahead und Lookbehind? Nein. Gos standardmäßiges regexp-Paket verwendet die RE2-Engine, die überhaupt keine Lookarounds unterstützt, um lineare Laufzeit zu garantieren. Muster mit (?=...) oder (?<=...) werden in Go nicht kompiliert. Strukturieren Sie die Logik mit Erfassungsgruppen um oder verwenden Sie eine Drittanbieter-PCRE-Bindung, wenn Sie Assertionen wirklich benötigen.

Wann sollte ich Lookahead anstelle einer Erfassungsgruppe verwenden? Verwenden Sie Lookahead, wenn der benachbarte Text nur eine Bedingung ist und Sie ihn nicht im Ergebnis haben möchten. Verwenden Sie eine Erfassungsgruppe, wenn Sie den umgebenden Text im Treffer haben und einen Teil davon isolieren möchten. Beispiel: \d+(?=USD) gibt nur die Zahl zurück, während (\d+)USD die Zahl zurückgibt, aber USD im Gesamttreffer behält.

developerregex-testerregexweb-development

More from Molixa

Try Molixa Tools

50+ free AI tools for content creation, SEO, coding, and more. No signup, no watermark.

Explore all tools
Regex Lookahead & Lookbehind erklärt | Molixa | Molixa