Positive and Negative Lookahead — (?=...) and (?!...) Explained
Deep dive into positive lookahead (?=...) and negative lookahead (?!...) with worked examples for password rules, file extensions, and conditional matching.
Detailed Explanation
Positive and Negative Lookahead
Lookahead assertions are zero-width: they check what comes next without consuming characters. They are essential for password validation, conditional matching, and avoiding overlapping matches.
Positive Lookahead (?=X)
Matches a position where X can be matched immediately to the right.
\d+(?=px)
Matches digits only when followed by px. In "100em 200px 300rem", only 200 matches.
Negative Lookahead (?!X)
Matches a position where X cannot be matched immediately to the right.
\d+(?!px)
Matches digits NOT followed by px. In the same string, 100 and 300 match.
Multiple Lookaheads (Password Validation)
The classic use is composing requirements:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%]).{8,}$
Each lookahead independently verifies one rule (lowercase present, uppercase present, etc.) and the trailing .{8,} enforces length.
Tested Examples
| Pattern | Input | Match |
|---|---|---|
\d+(?=px) |
"font: 14px" |
14 |
\d+(?!px) |
"100em" |
100 |
(?=.*foo)(?=.*bar).+ |
"foo and bar" |
full string |
| `file(?=.(txt | md)$)` | "file.txt" |
\b\w+(?!\w) |
"end." |
end |
Why Zero-Width Matters
Because lookaheads do not consume characters, they are perfect for asserting conditions without affecting subsequent matches. (?=X)Y matches Y only if X precedes the position where Y would match.
Avoid Common Pitfalls
- Lookaheads anchored at
^re-scan from the start for each one, which can be slow on large inputs - Variable-length lookaheads are supported in JavaScript, unlike some other engines
- Lookaheads do not capture; you cannot reference them with
$1
Practical Use Cases
- File-extension matching:
.+(?=\.pdf$)extracts the basename - Skip-pattern:
(?!skip).+matches anything not starting with "skip" - Composable rules: each requirement is a separate lookahead clause
Use Case
Validating complex password policies, matching file names by extension without including the extension in the capture, or implementing skip rules in a regex-based filter.