Lookbehind (?<=...) and (?<!...)
A lookbehind (?<=X) requires X immediately before the current position without including it in the match; (?<!X) requires that X is not there. (?<=\$)\d+ matches the digits after a dollar sign and (?<!-)\b\d+ matches numbers without a minus. JavaScript supports lookbehind since ES2018 (Safari 16.4+); Python's re requires fixed-width lookbehind.
Syntax
(?<=X) positive (?<!X) negativeExamples
"cost $45, tax $5, qty 3".match(/(?<=\$)\d+/g)Result: ["45", "5"]
The dollar sign is required but not part of the match.
"5 -3 10 -7".match(/(?<!-)\b\d+/g)Result: ["5", "10"]
"user: jane".replace(/(?<=user: )\w+/, "anon")Result: "user: anon"
Replace only the value, keeping the label.
"2024-03-15".match(/(?<=-)\d+(?=-)/)[0]Result: "03"
Lookbehind and lookahead together isolate the middle part.
Common mistakes
- Python error "look-behind requires fixed-width pattern": (?<=\w+) is not allowed in re; JavaScript and .NET accept variable width.
- Older Safari and iOS (before 16.4) throw a SyntaxError on any lookbehind; use a capture group when you must support them.
- Confusing (?<=...) with a named group (?<name>...): the equals sign makes it a lookbehind.
- Using lookbehind where a plain capture is clearer and more portable, such as \$(\d+) and reading group 1.
Practice Lookbehind (?<=...) and (?<!...)
These drills check your answer on live data, free, no account needed.
- Lookbehind: amounts after $Match every amount that comes right after a dollar sign: digits with optional two-digit cents. The whole match is compared, so it must not include the $.
- Negative lookbehind: positive numbers onlyMatch every whole number that does not have a minus sign directly in front of it. Do not match the tail end of a negative number.
- Escaping: a price like $4.99The whole line must match. Match a dollar sign, one or more digits, a period and exactly two digits.
Questions
How do I match text after a specific word?
(?<=word )\w+ matches the word that follows, without including the marker. Without lookbehind support, use word (\w+) and read group 1.
Does Python support variable-length lookbehind?
The built-in re module does not; each alternative must have a fixed width, so (?<=a|bc) fails. The third-party regex module allows variable width.
How do I match text between two strings?
(?<=start).*?(?=end) returns only the middle. The capture-group version start(.*?)end works in every engine.
Related
- Lookahead (?=...) and (?!...)How lookahead checks what follows without consuming it: numbers before a unit, words without a prefix, thousands separators and file name filters.
- Escaping special charactersThe regex metacharacters that must be escaped, how to match a literal dot, dollar, plus or slash, what changes inside brackets, and how to escape user input.
- Named groups (?<name>...)How to capture by name, read match.groups.name, use $<name> in replacements and \k<name> as a backreference, and the (?P<name>) syntax Python needs.
- Regex in Python (re)How the Python re module works: search versus match versus fullmatch, findall and its group behavior, sub for replacement, raw strings, and flags.