Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Vim how can I search and replace every other match?

Say I have the following file

<block>
    <foo val="bar"/>
    <foo val="bar"/>
</block>
<block>
    <foo val="bar"/>
    <foo val="bar"/>
</block>

How could I make that into

<block>
    <foo val="bar1"/>
    <foo val="bar"/>
</block>
<block>
    <foo val="bar1"/>
    <foo val="bar"/>
</block>

One thing I tried to do was record a macro with :%s/bar/bar1/gc and press y and n once each and then try to edit that macro. For some reason I cannot edit the macro. :(

like image 597
Osada Lakmal Avatar asked Dec 07 '12 13:12

Osada Lakmal


People also ask

How do I find and replace every incident of a text string in Vim?

When you want to search for a string of text and replace it with another string of text, you can use the syntax :[range]s/search/replace/. The range is optional; if you just run :s/search/replace/, it will search only the current line and match only the first occurrence of a term.

How do I repeat and replace in Vim?

Change and repeat Search for text using / or for a word using * . In normal mode, type cgn (change the next search hit) then immediately type the replacement. Press Esc to finish. From normal mode, search for the next occurrence that you want to replace ( n ) and press . to repeat the last change.

How do I repeat a search in Vim?

You can now edit the search pattern and press Enter. Use Ctrl-r Ctrl-w for a <cword>, or Ctrl-r Ctrl-a for a <cWORD>. After searching, press Ctrl-o to jump back to your previous position (then Ctrl-i will jump forwards). After searching, an empty search pattern will repeat the last search.


1 Answers

Just to show that this can be done in a substitution:

:let a = ['', '1']
:%s/bar\zs/\=reverse(a)[0]/g

Overview

Replace at the end of every bar with the first element of array in variable a after the array is reversed in-place upon every substitution.

Glory of Details

  1. let a = ['', '1'] define an variable a to hold our array
  2. %s/.../.../ do a substitution on every line in the file
  3. %s/bar\zs/.../ do a substitution on bar but start the replacement after bar using \zs
  4. \= inside the replacement portion of the :s command uses the value of the following expression
  5. reverse(a) reverse simply reverses the array, but does so in-place
  6. reverse(a)[0] reverse returns the now reversed array so get the first element
  7. /g replace all occurances in the line (optional)

General Case

:let a = ['a', 'b', 'c']
:%s/bar\zs/\=add(a, remove(a, 0))[-1]/g

The general case "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
like image 159
Peter Rincker Avatar answered Oct 20 '22 18:10

Peter Rincker