Answer
:%s/\vfoo\zsbar/baz/g
Explanation
When your match has a stable prefix but you only want to replace the trailing segment, \zs is often cleaner than introducing extra capture groups. It resets the start of the effective match at a specific point, so the prefix still constrains where matching happens but is not included in the replacement. This keeps substitutions readable in long patterns and reduces backreference noise.
How it works
:%s/.../.../gruns substitution across the whole buffer\venables "very magic" mode so most regex atoms need less escapingfoo\zsbarmeans: matchfoofirst, then set the start of the replaceable match atbar- Because the effective match starts at
\zs, onlybaris replaced greplaces all occurrences on each line
Example
Input:
foo_bar foo_bar foo_baz
Command:
:%s/\vfoo\zs_bar/-qux/gOutput:
foo-qux foo-qux foo_baz
Notice that foo is required for a match but remains unchanged.
Tips
- Pair
\zswith\zewhen you need to isolate a middle segment - This pattern scales better than
\(foo\)barwhen your prefix becomes complex - Use
cflag (.../gc) for confirmation when refactoring code-like text
category: search tags: #search #ex-commands #formatting #editing
Next
How do I open another file without changing the alternate-file mark (#)?
Related Tricks
How do I search non-greedily across multiple lines between two markers?
/\vstart\_.{-}end
How do I search only the message part of TODO comments using match boundaries?
/\vTODO:\s*\zs.{-}\ze\s*($|#)
How do I search for 'bar' that is not preceded by 'foo'?
/foo\@<!bar
How do I restrict a search to a specific line-number window without selecting text first?
/\%>20l\%<40lTODO
How do I run vimgrep across a project using whatever pattern is currently in the search register?
:execute 'vimgrep /' . @/ . '/gj **/*'
