vimtricks.wiki Concise Vim tricks, one at a time.

How do I write a Vim regex lookahead that doesn't consume a capture group slot?

Answer

\%(pattern\)\@=

Explanation

Vim's lookahead assertion \@= confirms that the current position is followed by a pattern — without including those characters in the match. When combined with a non-capturing group \%(…\), the lookahead uses no capture group slot, keeping your \1, \2, … backreferences available for the parts of the match you actually care about.

How it works

  • \%(…\) — a non-capturing group: groups atoms for quantifiers or assertions without storing a backreference
  • \@=positive lookahead: succeeds if the preceding atom matches at the current position without consuming characters
  • Together, \%(pattern\)\@= checks whether the upcoming text matches pattern, but neither consumes those characters nor stores them as \1

Contrast with the capturing form \(pattern\)\@=, which wastes a capture slot. When your pattern already uses \1, \2, etc. for substitutions, every extra \(…\) pushes your real captures to higher numbers — making patterns harder to read and maintain.

Example

Match a word that is immediately followed by a colon, and capture only the word (not the colon):

/\(\<\w\+\>\)\%(:\)\@=

Here \1 contains just the word. If you used \(:\)\@= instead, \2 would be wasted on the lookahead group.

In a substitution — prefix every label-style identifier (e.g. foo:) with >> without touching the colon:

:%s/\(\<\w\+\>\)\%(:\)\@=/>>\1/g
Before:  foo: bar: baz
After:   >>foo: >>bar: >>baz

Tips

  • Use \%(pattern\)\@! for a negative lookahead (match only when NOT followed by pattern)
  • Use \%(pattern\)\@<= for a non-capturing lookbehind
  • Switch to \v (very magic) to drop most backslashes: \v%(pattern)@=
  • Vim's help: :help /\@= and :help /\%(

Next

What is the difference between the inner word (iw) and inner WORD (iW) text objects in Vim?