4

I have several lines that look like the following:

"Timestamp": 200,
"Timestamp": 1200,
"Timestamp": 3100,

I want to replace all the numbers, starting at 10 and incrementing by 10's so it looks like this:

"Timestamp": 10,
"Timestamp": 20,
"Timestamp": 30,
NH86Pen
  • 41
  • 1
  • 2
  • Related: https://vi.stackexchange.com/q/12867/10604, https://stackoverflow.com/q/4951533/4400820, etc. (search "vim substitute increment") – D. Ben Knoble Dec 14 '21 at 21:02

3 Answers3

4

I am not sure if you are looking for pure :%s/// solution or not.

I would approach this with 10 + g + <C-a>:

  1. replace all numbers with 0: :%s/\d\+,/0,
  2. select all zeroes and increment them by 10: 10g<C-a>

enter image description here

Maxim Kim
  • 13,376
  • 2
  • 18
  • 46
3

You can use a Vimscript variable and increment it after each substitution. By using the :g command with a pattern, you can follow it with both a :s to replace the number (using \= in the replacement part to use the Vimscript variable) and also a :let command to increment the variable.

:let a = 10 | g/^"Timestamp": \zs\d\+\ze,$/ s//\=a/ | let a += 10

See:

  • :help :bar (the bar | is used as a command separator in Vimscript.)
  • :help :let to assign and increment a Vimscript variable.
  • :help :g (the :global command executes another Ex command for each matching line.)
  • :help /\zs and :help /\ze: these markers mark the start and end of the match in a regular expression.
  • :help :s for the substitute. The empty pattern // makes it reuse the same pattern from the :g command.
  • :help sub-replace-expression for using \= in a substitution replacement to evaluate a Vimscript expression.
filbranden
  • 28,785
  • 3
  • 26
  • 71
  • How would you reverse this expression correctly? For example, what if the number was to the left of the colon, like 0 : "Timestamp" ?

    Would this work?

    :let a = 10 | g/ : \zs\d+\ze,$/ s//=a/ : "Timestamp" | let a += 10

    – AdjunctProfessorFalcon Jun 01 '23 at 19:12
  • 1
    @AdjunctProfessorFalcon You can use e.g. /\d\+\ze\s*: "Timestamp"/ as the pattern in that case, so g/\d\+\ze\s*: "Timestamp"/ s//\=a/ for the middle part of the expression. You don't need to change the :s command at all, only the pattern given to :g and make sure you still use \ze (and \zs if appropriate) to isolate the number you want to replace. – filbranden Jun 02 '23 at 16:38
3

One more way, using a macro:

First set the unmamed register to contain zero:

:let @n=0

Then record into a register of your choice (but not the 'n' register, since we're using that above! e.g. qa to use the 'a' register) the following macro (where ^A is pressing 'ctrl'+'a'):

0Wdt,"nP10^A"nyiwj

The way it works is as follows:

  • 0W moves to the start of the line, then jumps to the number
  • dt, deletes the existing number
  • "nP pastes the contents of the 'n' register (which we initally set to zero)
  • 10^A increment the number we just pasted by 10
  • "nyiw replace the contents of the 'n' register by the incremented number
  • j move down to the next line

Now you can run apply the macro to all the remaining lines:

:2,$norm @a
mattb
  • 1,111
  • 4
  • 15