本页面有中文版。
Cette page est disponible en français.
Esta página está disponible en español.
Guides1 live hunt inside

Regex lookahead and lookbehind, explained with live boards

Lookarounds let a regex check what comes before or after a spot without matching it. Here's how all four work, where they shine, and when a plain pattern is shorter.

Regex Hunter logo

· 7 min read

/q(?!u)/

match

  • iraq
  • qatar
  • qi

spare

  • queen
  • quiet
  • quote

Most of a regex consumes text. cat eats three characters, \d+ eats every digit it can, and the engine moves past whatever it matched.

Lookarounds don't. They stand at one spot in the string, peek forward or backward, and report yes or no. They match zero characters. That one idea lets you say things a plain pattern can't, like "a q that isn't followed by a u" or "a number that comes right after a dollar sign, without the dollar sign".

Every example below is live: edit the pattern and the lines update, or hit Try it to open it in the Playground.

01The four lookarounds

Syntax Name Succeeds when…
(?=X) positive lookahead X comes next
(?!X) negative lookahead X does not come next
(?<=X) positive lookbehind X comes right before
(?<!X) negative lookbehind X does not come right before

The arrow in the name tells you the direction: lookahead checks the text after the current position, lookbehind checks the text before it. = means "must be there", ! means "must not be there".

02Negative lookahead: a q without a u

In English, q is almost always followed by u. Catching the exceptions is a one-liner with a negative lookahead:

Matches6/6 as expected
/q(?!u)/

Should match3/3

  • iraq
  • qatar
  • qi

Should not3/3

  • queen
  • quiet
  • quote
Try it in the Playground
The (?!u) checks the character after the q, but doesn't match it. "iraq" passes because nothing follows its q.

Notice iraq. A tempting alternative is q[^u], "a q followed by anything except u". But [^u] has to match a character, and the q in iraq is the last letter. The lookahead only asks that the next thing isn't a u, and the end of the string isn't a u.

03Positive lookahead: match one part, check the next

A positive lookahead lets you require some context without including it in the match. Here we want the number, but only when it's an amount in dollars:

Matches3/3 as expected
/\d+(?= dollars)/

Should match1/1

  • it costs 40 dollars

Should not2/2

  • 40 euros
  • dollars 40
Try it in the Playground
Only "40" is matched in the first line. " dollars" is checked, not consumed.

This matters whenever you replace or extract text. Run a find-and-replace with \d+(?= dollars) and you change the number, while the word "dollars" stays exactly as it was.

04Stacking lookaheads: several rules at once

Because lookaheads don't move the position, you can put several at the same spot. Each one checks a different rule over the whole string. This is the classic password check: at least one digit, at least one uppercase letter, and eight or more characters:

Matches5/5 as expected
/^(?=.*\d)(?=.*[A-Z]).{8,}$/

Should match2/2

  • Hunter2024
  • Regex1Hunter

Should not3/3

  • hunter2024
  • SHORT1
  • NoDigitsHere
Try it in the Playground
Two lookaheads at the start each scan the whole string for one requirement. Then .{8,} checks the length.

Read it left to right: from the start, somewhere ahead there's a digit; from the same start, somewhere ahead there's a capital; then match 8 or more characters to the end. Order doesn't matter, which is exactly why lookaheads beat writing out every arrangement.

05Lookbehind: check what came before

Lookbehind is the mirror image. (?<=\$)\d+ matches digits that come right after a dollar sign, without the $ itself:

Matches3/3 as expected
/(?<=\$)\d+/

Should match2/2

  • $42
  • price: $7

Should not1/1

  • 42 apples
Try it in the Playground
The match is just the digits. The $ is required, but it stays out of the result.

And the negative form finds numbers that are not prices:

Matches4/4 as expected
/(?<!\$)\b\d+\b/

Should match2/2

  • 42 apples
  • year 2026

Should not2/2

  • costs $42
  • $100
Try it in the Playground
(?<!\$) rejects any number with a $ directly in front of it. The \b on each side stops it from matching the "00" inside "$100".

That last caption hides a real trap. Without the word boundaries, (?<!\$)\d+ would happily match 00 in $100, because the 0s aren't directly after the $. Lookbehind only checks the spot where the match starts, so you often need \b or an anchor to pin that spot down.

06When lookarounds win at golf, and when they don't

In regex golf, every character counts, so it's worth knowing when a lookaround pays for itself.

For two letters in any order, a plain alternation is shorter: a.*e|e.*a is 9 characters, and (?=.*a).*e is 10. But the number of orderings grows fast (2 for two letters, 6 for three, 24 for four), while each extra lookahead costs a fixed seven characters. Here's a board where every monster contains an a, an e and an i, in any order:

Compare64% shorter

Boardcertain · machine · relation · dialect · patience vs garden · pencil · plastic · money · violin

  1. every ordersolves it47
    /a.*e.*i|a.*i.*e|e.*a.*i|e.*i.*a|i.*a.*e|i.*e.*a/
  2. lookaheadssolves it17
    /(?=.*a)(?=.*e).*i/
Try the short one
Six orderings spelled out cost 47 characters. Two lookaheads and a final .*i cost 17.

The lookahead version works because a regex search tries each position in turn. At the very first position, both lookaheads scan the whole word, so it doesn't matter where the a and e are.

07Your turn

Same idea, new board. Every monster has at least one digit and at least one capital letter, in either order:

Live huntpar 15

Catch the words that have a digit and a capital letter, in any order.

Targets · 0/5 caught

  • Hunt3rtarget
  • R2d2target
  • x9Ytarget
  • Agent47target
  • 7Seastarget

Innocents · 0 hit

  • hunterinnocent
  • r2d2innocent
  • AGENTinnocent
  • 1999innocent
  • x9yinnocent

Type a regex — the board updates as you go.

Try it in the Playground
Like this? A new one drops every day.Play today’s hunt

08Things to know before you use them

  • Lookarounds are zero-width. (?=\d) on its own matches an empty string in front of a digit. That's handy for inserting text (like thousands separators) and confusing when you expected to match the digit itself.
  • Support varies. JavaScript (all modern browsers and Node), Python, Java, .NET and PCRE all support lookahead and lookbehind. Python's built-in re module only allows fixed-width lookbehind, so (?<=\$\d*) is an error there, while JavaScript accepts it. Go's standard regexp package supports no lookarounds at all.
  • Prefer the plain pattern when it's clear. q[^u]|q$ works too, and some readers find it easier to follow. Use a lookaround when it makes the intent obvious or saves real complexity.

09Keep practising

  • The regex guide has a quick reference with more live examples.
  • Lookarounds turn up on harder daily boards. Today's hunt might need one.