Lookarounds
Peek without consuming — lookahead and lookbehind are zero-width assertions that check what comes before or after a spot, then step back and let the real match continue.
Read the rules: Lookahead & lookbehind in the Guide →Drill it: Regex wizardry →
Builds on Groups & backreferences
What you'll learn
Steps · 12
- 01Peeking without consumingBriefing
- 02Positive lookaheadHunt
- 03Lookahead for a characterHunt
- 04Negative lookaheadHunt
- 05"Not followed by"Hunt
- 06Positive lookbehindHunt
- 07Negative lookbehindHunt
- 08Combining assertionsHunt
- 09A stricter passwordHunt
- 10A word NOT ending in sHunt
- 11Golf: q not followed by uHunt
- 12Assertions, masteredBriefing
Lookahead and lookbehind in regex
Lookarounds let a regular expression check the text next to a position without making it part of the match. They are zero-width, like anchors: the check passes or fails, and the cursor stays where it was. The rest of the pattern then carries on from that same spot, as if the peek never happened.
A lookahead looks to the right. (?=...) requires that the text ahead matches, and (?!...) requires that it does not. A lookbehind looks to the left: (?<=...) requires the text before to match, and (?<!...) requires that it does not. JavaScript supports all four, and its lookbehind can be any length.
Use them when the context decides the match but should not be part of it: a number only when a unit follows, a word only when a certain prefix is missing, or several rules on one input, such as a password that needs a digit and a capital letter in any order. In a hunt, a lookaround often spares the innocents that share every letter with the targets.
Examples
Catches
- 12px
- 300px
- w: 8px
Spares
- 12em
- px12
- 12 px
The lookahead demands
pxright after the digits, yet the match itself is only the number.Catches
- #tag
- go #team
- #2026
Spares
- tag
- # team
- a#
The lookbehind checks for
#to the left and leaves it out, so the match is the bare tag.Catches
- hello
- snake_case
Spares
- r2d2
- top10
The negative lookahead scans the whole word first with
.*, so a digit anywhere in it is enough to reject it.Catches
- play
- display
- player
Spares
- replay
- replays
The negative lookbehind spares
playonly whenresits directly before it.
Common mistakes
- Forgetting `. *
in a start-of-text lookahead.^(?=\d)checks only the first character; write^(?=.*\d)` to mean a digit appears anywhere. - Expecting the peeked text in the result. A lookaround never adds characters to the match, so a replace on
\d+(?=px)swaps the number and keeps thepx. - Copying a JavaScript lookbehind into another flavour. Python's
remodule needs a fixed length inside(?<=...), and many other flavours limit it, so(?<=\$\d*)works in JavaScript but fails there.
Read the rules: Lookahead & lookbehind in the Guide →Drill it: Regex wizardry →
Read more: Regex lookahead and lookbehind, explained with live boards →
Read more: Password rules with regex lookaheads (and when not to) →