1

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?

  • I'm sure we have a duplicate on this site but I don't find it... – statox Mar 13 '18 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 Mar 13 '18 at 16:13
  • 1
    ...ugh: ce not ciw. Or if the match is more complicated than foo I might use cgn. – Rich Mar 13 '18 at 16:29
2

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. – user3342816 Mar 13 '18 at 14:23
  • Neat! This is much simpler than my old answer on SO -- which supports back references though. – Luc Hermitte Mar 13 '18 at 15:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.