How do I search for a pattern only when it's preceded or followed by another pattern?
Answer
/\(pattern\)\@<=target or /target\(pattern\)\@=
Explanation
Vim supports zero-width assertions (lookahead and lookbehind) in its regex engine. These let you match text only when it appears near another pattern, without including that context in the match itself.
Lookbehind: match after a pattern
" Match 'bar' only when preceded by 'foo'
/\(foo\)\@<=bar
" With very magic mode (cleaner syntax)
/\v(foo)@<=bar
Lookahead: match before a pattern
" Match 'foo' only when followed by 'bar'
/foo\(bar\)\@=
" With very magic mode
/\vfoo(bar)@=
Negative variants
" Match 'bar' NOT preceded by 'foo'
/\(foo\)\@<!bar
" Match 'foo' NOT followed by 'bar'
/foo\(bar\)\@!
Practical examples
" Find 'print' not inside a comment (not preceded by #)
/\(#.*\)\@<!print
" Find variable assignments (word followed by ' = ')
/\v\w+( \= )@=
" Find opening braces not preceded by 'if' or 'for'
/\v(if|for)@<!\s*\{
" Replace 'get' only when followed by uppercase (method names)
:%s/\vget([A-Z])@=/fetch/g
Tips
- Use
\v(very magic mode) to avoid excessive escaping @<=is lookbehind,@=is lookahead@<!is negative lookbehind,@!is negative lookahead- Lookbehind in Vim can have variable length (unlike most regex engines)
- Performance:
@<=with complex patterns can be slow on large files - Documented under
:help /\@=and:help /\@<=