["100", "50"] (numbers followed by 'px', but 'px' is not in the match)
Note Lookaheads are zero-width assertions -- they check what comes next without consuming characters. The looked-ahead text is not part of the match result. This means subsequent patterns can still match those characters.
positive lookaheadfollowed byassert aheadzero-width assertionconditional match
Negative Lookahead (?!)
syntax
pattern(?!ahead) matches pattern only if NOT followed by ahead
JS: ["3", "5"] (numbers NOT followed by ' cats')
Py: ["data.csv", "img.png"] (files that are NOT .exe)
Note Negative lookahead is excellent for excluding specific patterns. Watch for off-by-one issues -- ensure the lookahead checks the right position. Commonly used to exclude file types, keywords, or invalid suffixes.
negative lookaheadnot followed byexclude patternreject match
Positive Lookbehind (?<=)
syntax
(?<=behind)pattern matches pattern only if preceded by behind
example
JS: '$100 and EUR200'.match(/(?<=\$)\d+/g)
Py: re.findall(r'(?<=@)\w+', 'user@gmail and admin@corp')
output
JS: ["100"] (digits preceded by $)
Py: ["gmail", "corp"] (words preceded by @)
Note Lookbehinds check what comes BEFORE the match position without including it. In JavaScript, lookbehinds were added in ES2018 and are supported in all modern browsers. Python's re module requires fixed-width lookbehinds -- use the third-party regex module for variable-width.
positive lookbehindpreceded byafter prefixlook behindextract after symbol
Negative Lookbehind (?<!)
syntax
(?<!behind)pattern matches pattern only if NOT preceded by behind
example
JS: 'USD 100 and $200'.match(/(?<!\$)\b\d+/g)
Py: re.findall(r'(?<!\\)\n', 'line1\nline2\\\nline3')
output
JS: ["100"] (digits NOT preceded by $)
Note Useful for avoiding matches that follow a specific prefix. A classic use case is matching newlines that are not escaped (not preceded by a backslash).
negative lookbehindnot preceded byexclude prefixavoid after
Combining Lookaheads & Lookbehinds
syntax
(?<=prefix)pattern(?=suffix)
example
JS: 'price: [42] and size: [XL]'.match(/(?<=\[)\d+(?=\])/g)
Py: re.findall(r'(?<=\[)\w+(?=\])', '[hello] and [world]')
Note You can combine multiple lookarounds on the same position. A common pattern for password validation stacks multiple lookaheads: (?=.*[A-Z])(?=.*\d)(?=.*[@#$]).{8,} checks for uppercase, digit, and special character all in one pass.
true / True for 'MyP@ss1word', false / False for 'weakpass'
Note Each lookahead checks a different requirement without advancing the match position. All must pass before .{8,} consumes the string. This is a widely-used pattern but be cautious about catastrophic backtracking with very long inputs -- consider checking each requirement separately in code for production validation.