Glossary

Lookahead

A lookahead is a zero-width regex assertion that checks whether a pattern matches immediately after the current position, without including those characters in the overall match — the engine "looks ahead," confirms the condition, and then continues matching from the same spot it started. It comes in two forms: positive (?=...) and negative (?!...), with a symmetric pair — lookbehind, (?<=...) and (?<!...) — checking what comes before a position instead.

How it works

Because a lookahead doesn't consume input, it can be combined with an ordinary pattern to add a condition without changing what actually gets matched:

Positive lookahead: \d+(?=px)
Matches the digits in "16px" (matches "16"), but not in "16em"
— it requires "px" to follow, without including "px" in the match.

Negative lookahead: foo(?!bar)
Matches "foo" in "foo baz", but not in "foobar"
— it requires "bar" to NOT follow.

A classic real-world use is password-strength validation, chaining multiple lookaheads that each check a different condition from the same starting position:

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

This requires at least one lowercase letter, one uppercase letter, one digit, and a minimum length of 8 — all four assertions are evaluated from position 0, and only the final .{8,} actually consumes (and thus matches) characters.

Common pitfalls

  • Lookaheads add real matching cost — chaining many of them, especially combined with greedy quantifiers inside each one, can contribute to catastrophic backtracking on pathological input.
  • Not all regex engines support lookbehind ((?<=...)), or support only fixed-length lookbehind — this is a common source of "works in JavaScript, fails in this other language" bugs.
  • Because a lookahead doesn't consume characters, forgetting that can lead to confusion about why the overall match is "too short" compared to what the pattern seems to describe.
  • A negative lookahead paired with a variable-length quantifier can still match a shorter substring the assertion happens to allow — \d+(?!px) does not reject "16px" outright, because after "16" fails the check, the engine backtracks to "1" and re-checks: "6px" doesn't start with "px", so "1" matches. Fixed-length or literal patterns (like the foo(?!bar) example above) don't have this backtracking trap.

Related terms

  • Regex — the pattern language lookahead is one assertion type within.
  • Capture group — a related but distinct construct: it captures and consumes text, where lookahead only checks and never consumes.

See also

  • Tool: Regex Tester — experiment with lookahead and lookbehind assertions with live match highlighting.