Lookahead and Lookbehind
In this chapter, we are going to explore more about finding matches in JavaScript. Learn the convenient ways of using Lookahead and Lookbehind in practice.
Understanding the advanced topics of JavaScript regular expressions is beneficial for any developer looking to enhance their coding skills. Among the more advanced and powerful features within this subject are lookahead and lookbehind assertions. These assertions enable developers to search for patterns in text without including those patterns in the result. This guide aims to provide an in-depth exploration of lookahead and lookbehind assertions in JavaScript, complete with numerous practical examples.
Regular expressions can be tricky, and edge cases may exist. Especially when you are using advanced concepts like Lookahead and Lookbehind. Use online regex testers or write unit tests to validate your expressions against a variety of input scenarios to ensure they behave as expected.
Introduction to Lookahead and Lookbehind Assertions
Lookahead and lookbehind assertions are zero-width assertions, meaning they match a position within the string rather than actual characters. They allow us to assert whether a given pattern exists or does not exist at a specific point in the string. Note: Modern JavaScript engines (ES2018+) support variable-length lookbehind assertions, though some older environments may require fixed-length patterns.
There are four assertions, formed by combining direction (ahead/behind) with polarity (positive/negative):
| Assertion | Syntax | Meaning |
|---|---|---|
| Positive lookahead | (?=...) | The pattern must follow this point |
| Negative lookahead | (?!...) | The pattern must not follow this point |
| Positive lookbehind | (?<=...) | The pattern must precede this point |
| Negative lookbehind | (?<!...) | The pattern must not precede this point |
Why "zero-width" matters
Because assertions match a position and not characters, the text they check is never included in the match and the regex engine's read position does not advance past it. This is exactly what makes them useful: you can require context around a match without that context becoming part of the result. The snippet below shows the difference between a real capturing group and a lookahead — both verify that pie follows apple, but only the group consumes the text:
If you are new to the (...) group syntax, see Capturing groups — lookaround uses the same parentheses but adds ?=, ?!, ?<=, or ?<! right after the opening bracket.
Positive Lookahead
A positive lookahead assertion checks for the existence of a certain pattern ahead of the current position in the string. It is denoted by (?=...). The following example is a positive lookahead to find the word "apple" followed by the word "pie":
Javascript regexp lookaround corresponds to characters
Negative Lookahead
A negative lookahead assertion checks for the absence of a certain pattern ahead of the current position. It is denoted by (?!...). The following example is a negative lookahead to find the word "apple" not followed by the word "pie":
Javascript regexp the negative lookahead
Positive Lookbehind
A positive lookbehind assertion checks for the existence of a certain pattern behind the current position in the string. It is denoted by (?<=...). Below is a code sample to find the word "pie" that is preceded by the word "apple":
Javascript regexp the positive lookbehind
Negative Lookbehind
A negative lookbehind assertion checks for the absence of a certain pattern behind the current position. It is denoted by (?<!...). Here is a sample to find the word "pie" that is not preceded by the word "apple":
Lookahead and Lookbehind
Practical Applications of Lookahead and Lookbehind
Validating Password Strength
Ensuring strong passwords is a common requirement in web applications. Lookahead assertions can be used to validate various password conditions without consuming characters.
Here every (?=...) is a separate requirement checked from the start of the string. Because each lookahead is zero-width, all four scan the same text independently without interfering with one another, and the final [A-Za-z\d@$!%*?&]{8,} is what actually consumes the password. The ^ and $ anchors pin the check to the whole string, and {8,} is a quantifier requiring at least eight characters.
Formatting and Parsing Data
Lookahead and lookbehind assertions can assist in formatting and parsing complex data structures. A good example is inserting commas into a string of numbers for readability:
This works by replacing every empty position (\B, a non-word-boundary) that is followed by a group of three digits repeated to the end of the number. The trailing (?!\d) ensures we only match positions where the remaining digits divide evenly into threes, so no comma is placed at the very start.
Extracting the amount from a price
Lookbehind is ideal for grabbing a value that sits after a known marker without capturing the marker itself. Here we pull the numeric amount that follows a $ sign:
The (?<=\$) lookbehind requires a $ immediately before the number but leaves it out of the result, so each match contains only the figure. Compare this with using a capturing group — a group would force you to read the amount out of match[1], whereas the lookbehind puts the value directly in the match.
Acting only when something does not follow
Negative lookahead lets you act on a position based on what does not come next. This example replaces hello with HI only when it is not followed by world:
Related topics
- Capturing groups — the parentheses that lookaround syntax builds on.
- Anchors: string start and end —
^and$, often paired with lookahead in validation. - Quantifiers, +, *, ? and
{n}— controlling repetition inside and outside assertions. - Greedy and lazy quantifiers — how matching length interacts with lookaround.
Conclusion
Mastering lookahead and lookbehind assertions in JavaScript can significantly enhance your ability to manipulate and analyze strings. These powerful tools provide the flexibility to assert patterns without consuming characters, making them invaluable for complex text processing tasks. By leveraging these assertions, developers can create more efficient and effective regular expressions, leading to cleaner and more maintainable code.