# Substitution with math goes wrong

I have a large xhtml document that is broken into some 245 long paragraphs, each with a unique id in the form of "ud###"

``````<p class="windowbg" id="ud000">
<!--- lots of content --->
</p>
...
<p class="windowbg" id="ud244">
<!--- and a bit more --->
</p>
``````

Since each 'paragraph' is several times larger than the viewport, i wanted to add links at the top of each to enable jumping around.

Here's what i came up with:

``````%s/\"ud\(\d\{3}\)\">/\=submatch(0)."<a href =\"#ud".printf("%03d", submatch(1) - 1)."\">prev<\/a> <a href=\"#ud".printf("%03d", submatch(1) + 1)."\">next<\/a>"/
``````

Now, the problem is that it didn't work.

The first 9 replacements were perfect, with the relevant line coming out like this:

``````<p class="windowbg" id="ud001"><a href="#ud000">prev</a> <a href="#ud002">next</a>
``````

But from 010 to 017, they came out weird, the links off by two

``````<p class="windowbg" id="ud010"><a href="#ud007">prev</a> <a href="#ud009">next</a>
``````

Then 018 and 019 were perfect, 020 through 027 came out off by four, 028 and 029 were correct, 030 through 037 were off by 6...

I don't know how long the pattern holds, and I can't figure out why it shows up in the first place.

Any ideas? Is this some well known bug?

-

Octal numbers! Numbers starting with `0` are taken to be in octal. So, 00108 = 000810, and subtracting one, we get 000710 = 00078.

``````                                                    octal
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.
…
To avoid a leading zero to cause octal conversion, or for using a different
base, use str2nr().
``````

So, your substitution replacement will look like:

``````\=printf("%s <a href='#ud%03d'>prev<\/a> <a href='#ud%03d'>next<\/a>", submatch(0), str2nr(submatch(1)) - 1, str2nr(submatch(1)) + 1)/
``````

Note that you can use a single `printf` for the whole thing.

`str2nr` can take a base, but:

``````When {base} is omitted base 10 is used.  This also means that
a leading zero doesn't cause octal conversion to be used, as
with the default String to Number conversion.
``````
-
In hindsight, the source of the problem should have been obvious, what with the pattern I was seeing. I suppose it just never occurred to me that vim might bother to deal with any base other than decimal. That printf statement is amazing too. I have much to learn. – FitzmorrisPR Feb 25 at 8:19
Oh. Just a small quibble, in that the printf statement seems to treat the backslashes as literals, which left all the `<a>` tags unclosed. Easy enough to fix – FitzmorrisPR Feb 25 at 8:47
@FitzmorrisPR Oh, yeah, I used single-quoted strings, so I needn't have escaped the `/`. – muru Feb 25 at 8:48
@FitzmorrisPR Guess I was mistaken. I had to use double quotes for the format string, and escape the `/` before it worked correctly (or use a character other than `/` to separate `:s`'s patterns). – muru Feb 25 at 8:51

It's because Vim is interpreting the numbers as octal. See `:h octal`. The suggestion there is to use `str2nr()` so wrap your `submatch` calls

``````%s/\"ud\(\d\{3}\)\">/\=submatch(0)."<a href =\"#ud".printf("%03d", str2nr(submatch(1)) - 1)."\">prev<\/a> <a href=\"#ud".printf("%03d", str2nr(submatch(1)) + 1)."\">next<\/a>"/
^^^^^^^           ^                                                  ^^^^^^^           ^
``````
-