Vim/Nvim Number Arithmetic in Substitution
Contents
In this post, I want to share how to do number arithmetic quickly and get what you want in specified format. More specifically, the topic is:
How do we add, subtract, multiply or divide a value to each number in a range?
Suppose that we have the following numbers at the end of each line:
line 1: 10
line 2: 20
line 3: 30
line 4: 40
line 5: 50
How to we do arithmetic operation to those numbers at the end of each line quickly?
We can use expression in substitution command to do this task, for details, see
:h subreplaceexpression
inside Vim. The idea is that instead of substitute
what you search with a string, we will evaluate an expression and use the
evaluated result as the substitution string. The general syntax for
substitution is:
:s/PATTERN/REPLACE/[flag]
To use an expression in REPLACE string, you can start the replacement string
with \=
, and the following string will be interpreted as an expression by
Vim. If you have used capture groups in PATTERN
, you can retrieve the
captured text in the corresponding capture group with submatch()
function.
For example, submatch(1)
will return the text in the 1st capture group.
With all this knowledge, we can easily solve the above problem. For example, to add 2 to the number at the end of each line, do:
:1,5s/\v(\d+)$/\=submatch(1)+2
Similarly, to minus or multiply by 2:
:1,5s/\v(\d+)$/\=submatch(1)2
:1,5s/\v(\d+)$/\=submatch(1)*2
For division, things are a little different here, because the division
character /
is the same as the substitute delimiter. In order to use division
character in substitute expression, we can change the delimiter to other
characters, for example, to #
:
:1,5s#\v(\d+)$#\=submatch(1)/2.0
Note that for division, we need to divide those numbers by 2.0, not by 2. If you use two integers, Vim will use integer division, not float division^{1}.
One minor issue with the division result is that the result may have many
decimal digits. You may want to round it to fixed digit, e.g., 3 digit. This
can be easily accomplished with the printf()
function, and the whole command
looks like:
:1,5s#\v(\d+)$#\=printf('%.3f', submatch(0)/2.3)
References
 Number manipulation within Vim.
 Change delimiter in search and replace command.
 Increment a specific number in csv file.
 Rounding number in Vim.
 Round floats to one decimal.

For example, if we do
:echo 5/2
, we will get2
instead of2.5
. ↩︎