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
divs 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>
<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
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 string
someprefixin 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.
printfis a function that takes a format string and values for the format parameters.
"%s%X": The format string.
%smeans to print the parameter as a string.
%Xmeans to convert the parameter to a hexadecimal number in capital letters (
submatch(1): It retrieves the first matched group.
submatch(2) - 1: It retrieves the second matched group and subtracts one from it.