Substitute the n-th occurrence of a word in vim

To replace the nth occurrence of PATTERN in a line in vim, in addtion to the above answer I just wanted to explain the pattern matching i.e how it is actually working for easy understanding.

So I will be discussing the \(.\{-}\zsPATTERN\)\{N} solution,

The example I will be using is replacing the second occurrence of more than 1 space in a sentence(string). According to the pattern match code->

  1. According to the zs doc,

    \zs - Scroll the text horizontally to position the cursor at the start (left side) of the screen.

  2. .\{-} 0 or more as few as possible (*)

    Here . is matching any character and {} the number of times. e.g ab{2,3}c here it will match where b comes either 2 or 3 times.

    In this case, we can also use .* which is 0 or many as many possible. According to vim non-greedy docs, "{-}" is the same as "*" but uses the shortest match first algorithm.

  3. \{N} -> Matches n of the preceding atom

    /\<\d\{4}\> search for exactly 4 digits, same as /\<\d\d\d\d>

    **ignore these \<\> they are for exact searching, like search for fred -> \<fred\> will only search fred not alfred.

  4. \( \) combining the whole pattern.

  5. PATTERN here is your pattern you are matching -> \s\{1,} (\s - space and {1,} as explained just above, search for 1 or more space)

"abc subtring def"

    :%s/\(.\{-}\zs\s\{1,}\)\{2}/,/

OUTPUT -> "abc subtring,def"

# explanation: first space would be between abc and substring and second 
# occurence of the pattern would be between substring and def, hence that 
# will be replaced by the "," as specified in replace command above. 

You can do this a little more simply by using multiple searches. The empty pattern in the :s/pattern/repl/ command means replace the most recent search result.

:/word//word//word/ s//newWord/
or
:/word//word/ s/word/newWord/

You could then repeat this multiple times by doing @:, or even 10@: to repeat the command 10 more times.

Alternatively, if I were doing this interactively I would do something like:

3/word
:s//newWord/r

That would find the third occurrence of word starting at the cursor and then perform a substitution.


Replace each Nth occurrence of PATTERN in a line with REPLACE.

:%s/\(\zsPATTERN.\{-}\)\{N}/REPLACE/

For information,

s/\%(\(pattern\).\{-}\)\{41}\zs\1/2/

also works to replace 42th occurrence. However, I prefer the solution given by John Kugelman which is more simple -- even if it will not limit itself to the current line.