How do I run a substitution only within the exact columns of a visual selection, not the whole line?
Answer
:'<,'>s/\%Vpattern/replacement/g
Explanation
When you press : after making a visual selection, Vim inserts '<,'> to restrict the substitution to the selected lines. But this still replaces matches anywhere on those lines, even outside the selection. The \%V atom restricts matching to only the characters that were inside the visual selection — including the exact column range.
How it works
'<,'>— restricts to the line range of the visual selection\%V— a zero-width atom that matches only at positions inside the last visual selection- Together they restrict the substitution to exactly the highlighted region
This is especially powerful with visual block (<C-v>) selections, where '<,'> alone is meaningless for column restrictions.
Example
Given this text, with foo visually selected on both lines (columns 5–7 only):
aaa foo bbb foo
aaa foo bbb foo
Running :'<,'>s/foo/bar/g (without \%V) replaces all foo on those lines:
aaa bar bbb bar
aaa bar bbb bar
But :'<,'>s/\%Vfoo/bar/g replaces only the foo that was inside the selection:
aaa bar bbb foo
aaa bar bbb foo
Tips
- Works with linewise (
V), characterwise (v), and blockwise (<C-v>) selections \%Vmatches the selection from the most recent visual mode; reselect withgvif needed- Combine with
\%<Vand\%>Vto match just outside the selection boundaries - Works in search patterns too:
/\%Vpatternhighlights only matches inside the selection