Lookahead and Flags
~340 words ยท 2 min read
Lookahead and Flags
Lookaheads assert what comes next without consuming it, and flags change how the entire pattern behaves. Together they make regex far more expressive.
Lookahead
A lookahead (?=...) checks that the following text matches a pattern, but the assertion consumes no characters. The match position stays put.
/foo(?=bar)/ matches "foo" only when followed by "bar"
on "foobar": matches "foo"
on "foobaz": no match
Negative Lookahead
Negative lookahead (?!...) succeeds when the following text does NOT match. It is ideal for "must not contain" rules.
/foo(?!bar)/ matches "foo" only when NOT followed by "bar"
Lookarounds are zero-width assertions: they test a condition at a position without eating characters. That is why
foo(?=bar)matches just "foo" โ the "bar" is verified but left untouched for whatever follows.
Flags
Flags appear after the closing delimiter and modify matching behavior across the whole pattern.
gโ global: find all matches, not just the firstiโ case-insensitivemโ multiline:^and$match line boundariessโ dotall:.matches newlines too
/cat/gi all "cat", any case
/^error/m "error" at the start of any line
/.+/s matches across newlines
The Global Flag and State
The g flag makes a regex stateful in JavaScript โ exec() and lastIndex track position across calls. Reusing such a regex carelessly can skip matches or loop forever.
const re = /\d+/g;
re.exec("a1b2"); // ["1"], lastIndex becomes 2
re.exec("a1b2"); // ["2"]
re.exec("a1b2"); // null, lastIndex resets to 0
Putting It Together
A password rule like "at least 8 characters, containing a digit" combines lookaheads: /^(?=.*\d).{8,}$/. Master lookarounds and flags, and you can express validation logic that would otherwise need many lines of code.