JS RegExp Assertions
In this page:
Positive Lookahead: (?=...)
A positive lookahead, written (?=pattern), requires the main match to be immediately followed by the given pattern, but does not include that following text as part of the actual match result -- useful for matching a word only when a specific word comes right after it.
Note: Use lookahead when you need to check for context immediately following a match without that context becoming part of the captured result itself.
Warning: Beginners often expect the lookahead's content to appear in the match result -- it never does, since it is purely a condition, not a capturing part of the pattern.
Example: Positive Lookahead: (?=...)
console.log("100px".match(/\d+(?=px)/)); // matches digits only when followed by "px"
Negative Lookahead: (?!...)
A negative lookahead, (?!pattern), requires the main match to NOT be followed by the given pattern -- the opposite of a positive lookahead, useful for excluding a specific following context from an otherwise valid match.
Note: Use negative lookahead when a match should be rejected specifically because of what comes right after it, rather than because of the matched text itself.
Warning: A negative lookahead only checks immediately following context -- it cannot express "does not appear anywhere later in the string" on its own without additional pattern structure.
Example: Negative Lookahead: (?!...)
console.log("100em".match(/\d+(?!px)/)); // matches since NOT followed by "px"
Positive and Negative Lookbehind: (?<=...) and (?<!...)
Lookbehind works like lookahead but checks the text immediately BEFORE the match instead of after -- (?<=pattern) requires that preceding text to be present, and (?<!pattern) requires it to be absent, again without including that preceding text in the actual match result.
Note: Use lookbehind when the context that determines whether a match is valid comes before the text you actually want to capture, rather than after it.
Warning: Lookbehind was added to JavaScript later than lookahead -- while supported in all current major browsers, it is worth being aware of if you must support unusually old browser versions.
Example: Positive and Negative Lookbehind: (?<=...) and (?<!...)
console.log("$100".match(/(?<=\$)\d+/)); // "100", lookbehind for $
console.log("100".match(/(?<!\$)\d+/)); // "100", not preceded by $
Combining Assertions with the Main Pattern
Assertions are typically combined with a real, capturing part of the pattern -- the assertion establishes context, while the surrounding pattern defines what actually gets matched and returned, together forming a precise condition beyond what plain character matching alone can express.
Note: Think of an assertion as answering "is this the right context?" while the rest of the pattern answers "what exactly do I want to capture here?" -- keeping those two roles distinct clarifies pattern design.
Warning: Overusing multiple chained assertions in one pattern can make it significantly harder to read and debug -- sometimes splitting logic across two separate checks in code is clearer than one dense regex.
Example: Combining Assertions with the Main Pattern
console.log(/(?=.*\d).{6,}/.test("secret1")); // lookahead checks context, {6,} defines the real match
When Assertions Are the Right Tool
Assertions shine specifically when you need to match based on surrounding context without capturing that context -- extracting a price after a currency symbol, validating a password contains multiple different character types, or finding a word only when it is not part of a larger compound word.
Note: Reach for an assertion specifically when a normal capturing group would include unwanted extra text in your match result.
Warning: For simple cases where including the surrounding context in the match result would be fine (or even useful), a normal group is often simpler than reaching for an assertion.
Example: When Assertions Are the Right Tool
console.log("Price: $50".match(/(?<=\$)\d+/)); // extracts price after currency symbol without capturing the symbol itself
- Confusing a lookahead/lookbehind with a normal group -- the text they check against is not included in the actual match result, which surprises people expecting it to be captured.
- Mixing up positive assertions (?=...) and (?<=...) (must be present) with negative ones (?!...) and (?<!...) (must NOT be present).
- Assuming lookbehind support is universal without checking -- it was added to JavaScript later than lookahead and has slightly different browser support history.
- (?=...) is a positive lookahead: the match must be followed by the given pattern, without including it in the result.
- (?!...) is a negative lookahead: the match must NOT be followed by the given pattern.
- (?<=...) and (?<!...) are positive and negative lookbehind, checking what comes before the match instead of after.
Lookahead has been supported in every browser for a very long time; lookbehind is supported in all current major browsers, added somewhat more recently.
Chapter Quiz — Complete all 26 topics to unlock
0/26 topics done
Complete these topics first:
- JS JSON
- JS Regular Expressions
- JS Fetch API
- JS LocalStorage and SessionStorage
- JS Cookies
- JS setTimeout and setInterval
- JS Event Loop
- JS Web Workers
- JS Service Workers
- JS AJAX
- JS AJAX Intro
- JS AJAX XMLHttp
- JS AJAX Request
- JS AJAX Response
- JS AJAX XML
- JS AJAX PHP
- JS AJAX Database
- JS JSONP
- JS RegExp Flags
- JS RegExp Classes
- JS RegExp Metachars
- JS RegExp Assertions
- JS RegExp Groups
- JS RegExp Quantifiers
- JS JSON HTML
- JS JSON vs XML