问题
I saw other questions dealing with the finding the n-th occurrence of a word/pattern, but I couldn't find how you would actually substitute the n-th occurrence of a pattern in vim. There's the obvious way of hard coding all the occurrences like
:s/.*\(word\).*\(word\).*\(word\).*/.*\1.*\2.*newWord.*/g
Is there a better way of doing this?
回答1:
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.
回答2:
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.
回答3:
Replace each Nth occurrence of PATTERN in a line with REPLACE.
:%s/\(\zsPATTERN.\{-}\)\{N}/REPLACE/
回答4:
This answers your actual question, but not your intent.
You asked about replacing the nth occurrence of a word (but seemed to mean "within a line"). Here's an answer for the question as asked, in case someone finds it like I did =)
For weird tasks (like needing to replace every 12th occurrence of "dog" with "parrot"), I like to use recursive recordings.
First blank the recording in @q
qqq
Now start a new recording in q
qq
Next, manually do the thing you want to do (using the example above, replace the 12th occurrence of "dog" with "parrot"):
/dog
nnnnnnnnnnn
delete "dog" and get into insert
diwi
type parrot
parrot
Now play your currently empty "@q" recording
@q
which does nothing.
Finally, stop recording:
q
Now your recording in @q calls itself at the end. But because it calls the recording by name, it won't be empty anymore. So, call the recording:
@q
It will replay the recording, then at the end, as the last step, replay itself again. It will repeat this until the end of the file.
TLDR;
qq
q
/dog
nnnnnnnnnnndiwiparrot<esc>
@q
q
@q
回答5:
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.
回答6:
Well, if you do /gc
then you can count the number of times it asks you for confirmation, and go ahead with the replacement when you get to the nth :D
来源:https://stackoverflow.com/questions/3073865/substitute-the-n-th-occurrence-of-a-word-in-vim