# Replace same match with squential list

I find myself more then once doing this repetitive thing:

I have something like:

``````do amount_foo blah_blah
``````

I need to copy this n times, but change the `foo` part. I copy and paste it as many times as needed:

``````do amount_foo blah_blah
do amount_foo blah_blah
do amount_foo blah_blah
do amount_foo blah_blah
``````

Then a replace on one and one line:

``````:'<,'>s/foo/bar
:'<,'>s/foo/baz
:'<,'>s/foo/lot
``````

So I get:

``````do amount_foo blah_blah
do amount_bar blah_blah
do amount_baz blah_blah
do amount_lot blah_blah
``````

Is there a quicker way to do the same? Is there for example a way to pass a list to replace so that one could do:

``````:'<,'>s/foo/\=some_magic bar, baz, lot
``````

Easy enough to write a function for it, but there is perhaps a better way to do this natively?

• Commented Mar 13, 2018 at 14:07
• I'm sure we have a duplicate on this site but I don't find it... Commented Mar 13, 2018 at 14:23
• I'm presuming what you're actually doing is a bit more complicated than your example? (Because for this example I'd just do `/foo<CR>ciwbar<Esc>nciwbaz<Esc>...`)
– Rich
Commented Mar 13, 2018 at 16:13
• ...ugh: `ce` not `ciw`. Or if the match is more complicated than `foo` I might use `cgn`.
– Rich
Commented Mar 13, 2018 at 16:29

## 1 Answer

You are correct you can use a sub-replace-expression, `\=`, to do the list manipulation and replacement.

``````:let a = ['foo', 'bar', 'baz']
:%s/amount_\zsfoo/\=add(a, remove(a, 0))[-1]/
``````

This "rotates" the array, `a`, in-place and uses the last position of the array as the value for the replacement of the substitution.

For more help see:

``````:h :s
:h range
:h /\zs
:h :s\=
:h reverse(
:h :s_flags
:h Lists
:h add(
:h remove
``````
• Ah. That is simply sweet :) Especially that the list is kept. Commented Mar 13, 2018 at 14:23
• Neat! This is much simpler than my old answer on SO -- which supports back references though. Commented Mar 13, 2018 at 15:00