Replace text before and after pattern in one command in vim

Viewed 158

Let's say I have the following text

bar1 = foo.get('abc1')
bar2 = foo.get('abc2')
bar3 = foo.get('abc3')

and I would like to search and replace all the occurrences of foo.get(...) with foo[...] in order to obtain:

bar1 = foo['abc1']
bar2 = foo['abc2']
bar3 = foo['abc3']

How could I do that in vim in one search/replace command?

4 Answers

The following should work: :%s/foo.get(\(\W\+\)\(\w\+\)\(\W\+\))/foo\[\1\2\3].

Here, the main logic is to store ', abc1 and ' to \1, \2 and \3 which can later be back referenced. Similarly for other two lines.

The simplest way I think would be to select those three lines using VISUAL mode (press v, and hjkl/arrows to select the lines) - the advantage of visual mode is that you can select which lines to launch the substitute command on.

enter image description here

then press : to launch a command on those lines selected in visual mode (:'<,'>part should add itself automatically):

:'<,'>s/foo.get('\(.*\)')/foo['\1']

so this simple regex basically selects foo.get('somewords') and replaces them with foo['somewords'] (somewords being group 1)

Another solution would be:

:g/foo\.get/exec "norm! f(r[\<Esc>f)r]"

Let's break down the whole command to be more didactic:

 g/foo\.get/ .................... match all the lines with "foo.get"
 exec ........................... calls command execution
 norm! .......................... normal mode
 f(r[ ........................... jumps to the ( and replaces it with [
 \<Esc> ......................... literal Esc (only works between double quotes)
 f)r] ........................... the final substitution

If you just want a one shot regex for this specific pattern, you can use:

:%s/foo\.get(\(.*'\))/foo[\1]/c

or if there are possible spaces to contend with:

:%s/foo\.get *(\(.*'\) *)/foo[\1]/c

The /c is for a prompt to confirm the replacement, and can be left off if desired.

Related