Positive and Negative Lookbehind — (?<=...) and (?<!...) Explained
Deep dive into positive lookbehind (?<=...) and negative lookbehind (?<!...) with practical examples for currency, prefixes, and pre-context filtering.
Detailed Explanation
Positive and Negative Lookbehind
Lookbehind assertions check the text immediately preceding the current position without consuming it. They were added to JavaScript in ES2018 and are fully supported in modern engines (Node 10+, all current browsers).
Positive Lookbehind (?<=X)
Matches a position preceded by X.
(?<=\$)\d+(?:\.\d+)?
Extracts numeric prices that are preceded by $. In "Save $20 today", matches 20.
Negative Lookbehind (?<!X)
Matches a position NOT preceded by X.
(?<!\d)\.\d+
Matches .42 only when there is no digit before the dot (rejecting 3.14).
Variable-Length Lookbehind
Modern V8 supports variable-length lookbehinds:
(?<=https?:\/\/[^\s/]+)\/[^\s]+
Matches the path portion of a URL (anything after the host).
Tested Examples
| Pattern | Input | Match |
|---|---|---|
(?<=\$)\d+ |
"$100" |
100 |
(?<!#)[a-f0-9]{6} |
"hex abc123 not #abc123" |
abc123 (without #) |
(?<=class=")[\w ]+ |
'class="btn primary"' |
btn primary |
(?<=^)\d+ |
"123abc" |
123 |
(?<!\w)cat |
"a cat sits" |
cat |
Lookbehind vs Capture Group
You could match $100 with \$(\d+) and reference $1. The lookbehind version is cleaner when you want the match itself to exclude the prefix, which simplifies downstream code that uses match[0].
Combining with Lookahead
(?<=\$)\d+(?=\s|$)
Matches a price preceded by $ and followed by whitespace or end of string, ignoring $1234567890 embedded in larger strings.
Browser Support Note
Lookbehind shipped in V8 7.6 (Chrome 76, Node 10+), Safari 16.4, and Firefox 78. If you need to support older Safari, use a polyfill or rewrite with capture groups.
Practical Use Cases
- Extract values after a known prefix (currency, units, tags)
- Skip matches that are commented out (preceded by
//) - Find isolated occurrences of a substring
Use Case
Extracting prices preceded by a currency symbol from product descriptions, filtering matches that should not have certain prefixes (already-prefixed slugs), or pulling values out of HTML attributes without including the attribute name.