/^/

Lesson 15 of 28

Negative Lookbehind

Match a pattern only when it is NOT preceded by something specific, using negative lookbehind (?<!...).

5 min read

If lookbehind lets you say “match this, but only when it’s preceded by X,” negative lookbehind lets you say the opposite: “match this, but only when it is not preceded by X.” The syntax is (?<!...).

It’s the fourth and final lookaround form, and it’s especially useful for excluding a category of matches that would otherwise look identical to the ones you want.

Filtering out matches by what comes before them

Imagine you’re scanning a receipt for plain quantities, but you want to ignore any number that’s actually a dollar amount:

const text = "Price: $50, Quantity: 3, Code: 42";
const matches = text.match(/(?<!\$)\b\d+\b/g);
console.log(matches); // ["3", "42"] — "50" is skipped because it follows "$"
Price: $50, Quantity: 3, Code: 42
2 matches

The \b\d+\b part matches any standalone run of digits. The (?<!\$) in front adds a condition: don’t match here if the character immediately before is a $. Since 50 sits right after $, it’s excluded — but 3 and 42 are both preceded by a space, so they pass through untouched.

Positive vs. negative lookbehind

Pattern Matches “cat” when…
(?<=top )cat preceded by "top "
(?<!top )cat NOT preceded by "top "

Both are zero-width — neither one adds top (or its absence) to the actual match text. They only gate whether the match at that position is allowed to happen.

Watch out

Negative lookbehind can be easy to misread at a glance because (?<=...) and (?<!...) differ by a single character (= vs !). When debugging a pattern that isn’t matching what you expect, double-check you didn’t mix these up — it’s a common source of “why is this regex backwards” bugs.

Combining with other assertions

Negative lookbehind composes naturally with the rest of what you’ve learned. For example, to match a word that is not preceded by “not “ and not followed by “!”:

/(?<!not )\bfoo\b(?!!)/

This kind of chaining — lookbehind and lookahead stacked around a core pattern — is exactly how real-world validation regexes (like password rules) end up built.

Exclude a negated phrase

Given the text "I like foo but not foo today", write a pattern that matches "foo" only when it is not immediately preceded by "not ".

Show solution
/(?<!not )foo/g

Against that text, this matches only the first "foo" — the one preceded by "like ". The second "foo" is preceded by exactly "not ", so the negative lookbehind blocks it.

What’s next

You’ve now covered all four lookaround assertions. Next, we shift focus to how quantifiers actually behave during matching, starting with greedy matching — the default (and sometimes surprising) way *, +, and {n,} consume text.

Quick check

What does the pattern (?<!\$)\b\d+\b match in the text "Price: $50, Qty: 3"?

Negative lookbehind (?<!...) is best described as: