Regex Lookahead vs Lookbehind: Examples and Tutorial
The one-line difference
Lookahead checks what comes after the current position. Lookbehind checks what comes before it. Both are zero-width: they match a condition without consuming characters, so the rest of the pattern keeps working from the same spot.
Four constructs cover almost every use:
(?=...) positive lookahead - matches if ... follows
(?!...) negative lookahead - matches if ... does NOT follow
(?<=...) positive lookbehind - matches if ... precedes
(?<!...) negative lookbehind - matches if ... does NOT precedeRead them left to right: the ? opens a group, the = or ! sets the direction, and the extra < in lookbehind points the check backwards. That < is the whole visual difference between the two families.
When should you reach for one instead of the other? Think about what your eye does on the page. If you look at a price and want "the number that has a $ in front", that is lookbehind. If you scan a log and want "the word that is followed by a colon", that is lookahead. The syntax follows the direction your brain already points.
What zero-width actually means
Most regex tokens consume the text they match. A lookaround does not. The engine peeks at the surrounding text, confirms the condition, and continues the match from the original position.
\d+(?=px)This matches digits only when "px" follows them. It does not include "px" in the match:
Input: 12px 34em 56px
Matches: 12 34 56
(34 is skipped because "em", not "px", follows)Swap in lookbehind and the check moves to the other side:
(?<=\$)\d+This matches digits only when a dollar sign precedes them:
Input: $5 €10 $20
Matches: 5 20
(10 is skipped because "€", not "$", precedes)Because the lookaround is zero-width, the digits are the whole match. That is the behavior people usually want when they say "match the number, not the currency symbol." It also means you can stack lookarounds on the same position — (?<=\$)(?=\d{2}) requires both a dollar sign before and two digits after, and still matches nothing but what the middle pattern produces.
Positive lookahead (?=...)
The workhorse of lookarounds. Use it to require something after the match without including it. A classic is matching a word only when it is the last word of a sentence:
\w+(?=\.)Input: "End the sentence. Then continue."
Matches: sentenceOr requiring a minimum length while keeping the matched text clean:
(?=.*\d)[a-z]+This only matches lowercase runs in strings that contain at least one digit somewhere. The lookahead scans ahead, finds the digit, and lets the [a-z]+ proceed. Password validators use this shape constantly: several lookaheads, each enforcing one rule, none of them consuming the password itself.
Negative lookahead (?!...)
Use it to exclude a continuation. Matching "foo" not followed by "bar":
foo(?!bar)Input: foobar foobaz
Matches: foo (second one only)This pattern is everywhere in validation: "an address that does not end with .example", "a username that is not followed by a banned suffix." The negative lookahead is the cheapest way to say "anything but this." One caution: it checks a single position, so foo(?!bar) will still match the "foo" inside "foobar" if you test against a substring where the engine starts at the "foo" — run it against the full string and check the boundaries you actually mean.
Positive lookbehind (?<=...)
Requires a prefix without consuming it. Extracting numbers after a fixed label:
(?<=price: )\d+Input: price: 99 cost: 40 price: 12
Matches: 99 12Lookbehind is pickier than lookahead in most engines: the pattern inside must have a fixed length. (?<=\d{3}) is fine; (?<=\d+) is rejected in JavaScript and Python because the length is unknown.
Negative lookbehind (?<!...)
Matches only when a prefix is absent. The classic is "match a number not preceded by a minus sign":
(?<!-)\d+Input: 5 -3 7 -8 9
Matches: 5 7 9Same fixed-length rule applies. If you need a variable-length negative lookbehind, you usually restructure the pattern or fall back to a capture group and a check in code.
Lookahead vs lookbehind side by side
The same task solved twice, once in each direction, shows why the choice matters. Extracting the key from "key=value":
\w+(?==) # lookahead: key when "=" follows
(?<=\w+=)\w+ # lookbehind: value when "key=" precedesInput: user=alice role=admin
Lookahead: user role
Lookbehind: alice adminNeither is "better" — they answer different questions. Lookahead is for conditions on what follows, lookbehind for conditions on what precedes. Use the one that matches the sentence you would say out loud about the data.

One more practical difference: lookahead is free to roam. Because the engine already has the rest of the string in front of it, variable-length lookahead like (?=\w{2,}) is no trouble anywhere. Lookbehind has to rewind, which is exactly why engines impose the fixed-length rule on it. If a tool you are using rejects your lookbehind, that restriction, not your syntax, is usually the culprit.
Engine support and the fixed-length rule
Lookahead works everywhere, including JavaScript, Python, PHP, Ruby, and PCRE. Lookbehind is younger. JavaScript added it in ES2018, Python has supported fixed-length lookbehind since 3.5, and PCRE allows some variable-length forms. Go's regexp package has no lookaround at all, and neither does RE2 — if you are deploying to Go, plan around capture groups instead.
Three rules of thumb before you commit to a pattern:
- Test it in the target engine. A pattern that works in a PCRE tester can fail in Python or JavaScript for the same input.
- Keep lookbehind fixed-length. If the engine complains, the fix is usually a capture group plus a conditional check in code.
- Prefer capture groups for extraction. When you control the code,
(key)=(\w+)with groups 1 and 2 is simpler to read than two lookarounds.
Paste both variants into a regex lookahead explained guide or a live tester like this site's regex tester and watch the match positions change as you flip between the two directions.
FAQ
What is the difference between lookahead and lookbehind?
Lookahead checks text after the current position, lookbehind checks text before it. Both are zero-width, so neither consumes characters.
What does (?=...) mean in regex?
Positive lookahead: the match continues only if the pattern inside appears immediately after the current position.
What does (?<=...) mean in regex?
Positive lookbehind: the match is valid only if the pattern inside appears immediately before the current position.
Does JavaScript support lookbehind?
Yes, since ES2018. Older environments need a transpiled or rewritten pattern.
Why does my lookbehind pattern fail in Python?
Python's re module requires fixed-length lookbehind. Variable-length alternatives like (?<=\d+) raise an error; use a fixed pattern or a capture group instead.
Are lookarounds slow?
Usually not, but pathological patterns can backtrack heavily. Test against real input at expected scale before using them on hot paths.
Start with the positive forms — (?=...) and (?<=...) — until the syntax is comfortable, then add negatives. Most real patterns need one lookaround at most, and the simpler pattern is the one that survives contact with production data.