How do I match a pattern only when it is preceded or followed by another pattern, without including that context in the match?
Answer
\@=
Explanation
Vim's regex engine supports zero-width lookahead and lookbehind assertions using the \@ family of atoms. These let you assert context around a match without consuming characters — the cursor does not advance past them, and they are not included in substitution results or visual highlights.
How it works
| Syntax | Name | Meaning |
|---|---|---|
A\@= |
Positive lookahead | Match position if followed by A |
A\@! |
Negative lookahead | Match position if NOT followed by A |
A\@<= |
Positive lookbehind | Match position if preceded by A |
A\@<! |
Negative lookbehind | Match position if NOT preceded by A |
The assertion applies to the atom immediately before \@.
Example
Match only the argument list portion of function calls (the part after ( in foo(bar)), without matching the function name:
/\(\w\+(\)\@<=\([^)]*\)/
Or: delete the semicolon only at end-of-line positions (not inside strings):
:%s/;\(\s*$\)\@=/,/g
Highlight return only when NOT followed by a value (bare return;):
/return\(\s*;\)\@=
Match words that are not preceded by #:
/\(#\)\@<!\w\+
Tips
- These are distinct from
\zs/\ze(which set match start/end for substitution).\@=/\@<=are true zero-width assertions and work in:match,syn match,search(), etc. - For long lookbehind patterns, add a length limit before
\@<=:\{,20}matches up to 20 characters back:\(pattern\)\{,20}\@<= - Combine with
\%Vand\@<=for precision edits inside visual selections