Vim: Expressions in replacement text
Often times I find myself needing to modify the selection in a substitute command in a non-trivial way. From a recent example, I needed to convert the numbers in the id
of the div
s to hexadecimal after decrementing them by 1.
Basically, I had to convert
<div id="someprefix1">
...
</div>
<div id="someprefix2">
...
</div>
<div id="someprefix3">
...
</div>
<div id="someprefix4">
...
</div>
...
<div id="someprefix80">
...
</div>
to
<div id="someprefix0">
...
</div>
<div id="someprefix1">
...
</div>
<div id="someprefix2">
...
</div>
<div id="someprefix3">
...
</div>
...
<div id="someprefix4F">
...
</div>
Doing this manually is tiring, I could have used macros but I instead chose an even simpler approach.
Vim allows to use expressions in the replacement part of the substitute command if it starts with \=
. So, the replacement can be simply done using \=
and printf
. What I did was simply use the following command after selecting the text in a visual selection.
:'<,'>s/\v(someprefix)(\d+)/\=printf("%s%X", submatch(1), submatch(2) - 1)
The breakdown is as follows:
:'<,'>
: Sets the range to visual selection.s/
: Starts the substitution.\v
: Enables “very magic mode”. This allows for writing simpler regular expressions without having to escape special characters.(someprefix)(\d+)
: Captures the stringsomeprefix
in group 1 and the number that follows in group 2./
: Ends the search and starts replacement.\=
: Tells Vim to treat the following text as an expression.printf(
:printf
is a function that takes a format string and values for the format parameters."%s%X"
: The format string.%s
means to print the parameter as a string.%X
means to convert the parameter to a hexadecimal number in capital letters (%x
for small).submatch(1)
: It retrieves the first matched group.submatch(2) - 1
: It retrieves the second matched group and subtracts one from it.
References#
:help sub-replace-expression
:help submatch
:help printf
:help /magic
:help :s