I'm trying to learn how to use regex with vim, and I'm currently trying to do a search and replace. I have something like this:
aaaaaaa&sometext&...
aaaaaaaanothertext
(the a
s are actually whitespace at the beginning of the line, that I don't know how to print that here)
And I want to replace the first occurence of &
with & &
, and keep everyting else as is. I'm using \%(...\)
for non-capturing patterns, as suggested here, but the a
pattern is still captured. I'm using :%s/\%(^a*\)&/& &/gc
, and I get:
aaaaaaaa& aaaaaaaa&sometext&...
aaaaaaaaanothertext
I don't get why. I've also tried the replace with groups, as in :%s/\%(^a*\)\(&\)/\1 \1/gc
, but then I get:
& &sometext&...
aaaaaaaanothertext
So, it seems the group is indeed being ignored for the group handling (since the first group is on the search pattern is &
), but is still captured on the search pattern.
So, long story short, which replace command do I have to use to go from:
aaaaaaa&sometext&...
to:
aaaaaaa& &sometext&...
?
"Non-capturing" doesn't mean what you think it means. The only difference between \(...\)
and \%(...\)
is whether or not the subexpression is saved to \1
, \2
... It will still include the matched content in the match.
You wanted \@<=
(:help \@<=
):
:s/\(^a*\)\@<=&/\& \&/g
I want to replace the first occurrence of
&
with& &
, and keep everything else as is
Use a substitution command:
:s/&/& &/
Another tip: Vim by default treats (
as a literal character, rather than the start of a group.
Use very magic
mode if you want your regex to act more like traditional (Perl) regex.
An easy way to specify very magic
mode is to start your regex with \v
:
" this is a no-op
:s/\v(this is grouped)/\1/
EDIT: this answer works, but please see @heijp06's very relevant comment below (I wasn't aware that the &
character had a special meaning).
Comment pasted here:
It is actually somewhat nontrivial why this answer is correct. An & in the replacement part of a substitution means that what was matched by the pattern in this case that was an & so the end effect is correct.
Typically in search and replace, it's sufficient for the substitute to completely replace the search. In this case, your search will include things you don't want to replace.
Vim has helpful patterns to define the start and end of a match: \zs
and \ze
. You can place \zs
anywhere in the search, vim will only match after the start. You can use both to say, find this specific line and only replace a part of it.
And the solution:
:%s:^[^&]*\zs&:& &:c
%s
: Look at every line in the file ^[^&]*
: From the beginning of the line, there should be zero or more not &
\zs&
: The match to replace is a single &
& &
: Replace the match with two &
c
: Perform each substitution interactively in-case I suck at regexIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With