How do I replace each match with an incrementing number using a counter variable in Vim?
Answer
:let i=0 | g/pattern/s/pattern/\=printf('%d', i+=1)/
Explanation
By combining :let, the :g global command, and an expression substitution with \=, you can replace every match of a pattern with a unique incrementing number. This is useful for numbering items, tagging duplicates, or generating sequential identifiers without plugins.
How it works
:let i=0— initialises a counter variable to zero|— chains the next command on the same command line:g/pattern/— iterates over every line matchingpatterns/pattern/\=.../— substitutes the match using a Vimscript expressionprintf('%d', i+=1)— incrementsiand formats it as a decimal number
The \= in the replacement string tells Vim to evaluate the following expression, so each invocation gets a fresh value of i.
Example
Given this buffer:
FIX: crash on startup
FIX: memory leak in parser
FIX: incorrect return value
Running :let i=0 | g/FIX/s/FIX/\=printf('FIX-%02d', i+=1)/ produces:
FIX-01: crash on startup
FIX-02: memory leak in parser
FIX-03: incorrect return value
Tips
- Change
'%d'to'%02d'for zero-padded numbers like01,02,03 - Use
submatch(0)to reference the original matched text inside the expression:\=printf('[%d] %s', i+=1, submatch(0)) - The counter persists in Vimscript scope for the session, so re-run
:let i=0if you need to reset it - For non-sequential replacements, swap
i+=1with any Vimscript expression that returns a string