Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to non-capturing search and replace in vim

Tags:

regex

vim

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 as 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&...

?

like image 410
calofr Avatar asked Mar 24 '16 19:03

calofr


3 Answers

"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
like image 58
Amadan Avatar answered Nov 19 '22 02:11

Amadan


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.

like image 27
Jonathan.Brink Avatar answered Nov 19 '22 00:11

Jonathan.Brink


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 regex
like image 3
cdosborn Avatar answered Nov 19 '22 00:11

cdosborn