This is happening because Vim will automatically recognize and convert octal values.
From the help (:h variables
):
Conversion from a Number to a String is by making the ASCII representation of
the Number.
Examples:
Number 123 --> String "123"
Number 0 --> String "0"
Number -1 --> String "-1"
Conversion from a String to a Number is done by converting the first digits to
a number. Hexadecimal "0xf9", Octal "017", and Binary "0b10" numbers are
recognized. If the String doesn't start with digits, the result is zero.
Examples:
String "456" --> Number 456
String "6bar" --> Number 6
String "foo" --> Number 0
String "0xf1" --> Number 241
String "0100" --> Number 64
String "0b101" --> Number 5
String "-8" --> Number -8
String "+8" --> Number 0
Your values 02
through 07
are being recognized as valid octal values and preserved as such, decremented to octal 01
through 06
.
When you reach 08
it is not a valid octal value. It is treated as the string 08
, converted to decimal value 8
, and decremented to 7
. This happens again with 09
, which ends up being 8
.
The 10
and 11
values are decremented as decimal as well. Because 10
was decimal, not octal, you don't get a leading 0
in the resulting 9
value.
I'm not aware of a way to do what you want with the decrement command.
EDIT: After finding this answer, I tested this expression and it does what you are trying to do in this specific case:
:%s/\v[0-9]+/\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)/
I'm not sure whether this solves your general use case, because it's quite different from the original operation using a selection. But for the file you provided, it achieves the result you were after.
Dissecting this a bit to explain it:
First we start by calling the global sub command %s
and passing the \v
flag to turn on "very magic" mode. This may or may not change the behavior depending on your settings, but this is a public example, so it is included here to ensure that mode is active.
:%s/\v
Then, we find all the contiguous sequences of digits. This will find 02
, 03
, and so on from your example.
[0-9]+
Then in the replacement portion we have this command, which does the real work:
\=printf("%02d", substitute(submatch(0), '^0\+', '', 0)-1)
The substitute()
function determines what the new value is. submatch(0)
means to use the entire match. Using a pattern of ^0\+
and a replacement of (empty string) says to strip the leading zero from any number which has one. The 0
at the end isn't too important; it just says there are no flags to the substitute()
function.
The result of the substitute
command is a number. Say 02
has been stripped down to be 2
. Using the - 1
at the end, we subtract 1 from that result (decrement).
Finally, this result is passed to the printf
function. Using a format string %02d
says to print the values as decimal, in 2-digit wide format, padding with leading zeroes.