Here's one way to do it:
syntax match NumberX /\v<[1-9]\d{,2}\ze(\d{3})*>/ nextgroup=Number1
syntax match Number1 /\v\d{3}/ nextgroup=Number2 contained
syntax match Number2 /\v\d{3}/ nextgroup=Number3 contained
syntax match Number3 /\v\d{3}/ nextgroup=Number1 contained
hi NumberX guifg=red ctermfg=red
hi Number1 guifg=green ctermfg=green
hi Number2 guifg=blue ctermfg=blue
hi Number3 guifg=red ctermfg=red
NumberX
matches any number (that starts with a 1-9), but only highlights the first 1-3 digits, leaving a multiple of three digits remaining unhighlighted. The numbered groups then each highlight 3 digits, before looking for the next group in the series. I've set it up with three cycling colours, but you can easily use just two alternating, or add more in the cycle.
The regular expression broken down:
\v<[1-9]\d{,2}\ze(\d{3})*>
\v # Using very magic (so we don't need as many \ escapes)
< # Match the start of a word, followed by
[1-9] # any digit from one to nine, followed by
{,2} # up to two
\d # digits
\ze # End the match (so don't highlight what follows)
* # Then match as many as possible
( ) # groups
{3} # of three
\d # digits
> # leading up to the end of the word
In the :syntax
commands, nextgroup
tells Vim to test for the stated group immediately after the current match, and contained
means that the current group cannot be found at the top level: only when hinted via the nextgroup
keywords.
The possible downside of this solution is that it always highlights the start of the number in the same colour, and you'd probably want to always use the same colour for the end of the number (so, e.g. the thousands column is always the same colour).
Because Vim's syntax highlighting works by searching forwards through the file, a solution that fixes this issue needs to be a bit more complicated than the solution above. Here's one way to do it:
syntax match NumberA /\v<[1-9]\d{,2}\ze(\d{9})*>/ nextgroup=Number3
syntax match NumberB /\v<[1-9]\d{,2}\ze\d{3}(\d{9})*>/ nextgroup=Number2
syntax match NumberC /\v<[1-9]\d{,2}\ze\d{6}(\d{9})*>/ nextgroup=Number1
syntax match Number1 /\v\d{3}/ nextgroup=Number2 contained
syntax match Number2 /\v\d{3}/ nextgroup=Number3 contained
syntax match Number3 /\v\d{3}/ nextgroup=Number1 contained
hi NumberA guifg=blue ctermfg=blue
hi NumberB guifg=green ctermfg=green
hi NumberC guifg=red ctermfg=red
hi Number1 guifg=green ctermfg=green
hi Number2 guifg=blue ctermfg=blue
hi Number3 guifg=red ctermfg=red