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->
According to the zs doc,
\zs
- Scroll the text horizontally to position the cursor at the start (left side) of the screen..\{-}
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.\{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.\( \)
combining the whole pattern.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.