The problem can be solved by a counter separate from the one built-in into the
:substitute
command: Use Vim-script variable to hold the number of pattern
matches. A convenient way to register every match and modify a particular
variable accordingly, is to take advantage of the substitute with an
expression feature of the :substitute
command (see :help sub-replace-\=
).
The idea is to use a substitution that evaluates an expression increasing
a counter on every occurrence, and does not change the text it is operating
on.
The first part of the technique cannot be implemented straightforwardly
because it is forbidden to use Ex commands in expressions (including \=
substitute expressions), and therefore it is not possible to use the :let
command to modify a variable. Answering the question "gVim find/replace
with counter", I have proposed a simple trick to overcome that limitation,
which is based on using a single-item list (or dictionary containing a single
key-value pair). Since the map()
function transforms a list or a dictionary
in place, that only item could be changed in a constrained expression context.
To do that, one should call the map()
function passing an expression
evaluating to the new value along with the list containing the current value.
The second half of the technique is how to avoid changing text when using
a substitution command. In order to achieve that, one can make the pattern
have zero-width by prepending \ze
or by appending \zs
atoms to it (see
:help /\zs
, :help /\ze
). In such a way, the modified pattern captures
a string of zero width just before or after the occurrence of the initial
pattern. So, if the replacement text is also empty, substitution does not
cause any change in the contents of a buffer. To make the substitute
expression evaluate to an empty string, one can just extract an empty
substring or sublist from the resulting value of that expression.
The two ideas are put into action in the following command.
:let n=[0] | bufdo %s/pattern\zs/\=map(n,'v:val+1')[1:]/ge
tags, but it didn't work: `bufdo %s/\c
\ze//gen let n=[0]|bufdo %s//\=map(n,'v:val+1')[1:]/gen echo "number of
tags: " n[0] "\n"`
– labyrinth Nov 10 '11 at 05:43\ze/\=map(n,'v:val+1')[1:]/ge`.
– ib. Nov 10 '11 at 05:52\zs/\=[extend(g:, {'numptags': get(g:, 'numptags', 0)+1})][1:]/ge`.
– ZyX Nov 12 '11 at 11:44