1

Is there an easy way to search for all lines matching a pattern, extracting a number on the line, and modifying it?

I am playing around with a game config file and want to double all of the XP numbers to remove half of the boring grinding. The lines look like this (such as line 64 in the screenshot).

Experience points: ###

And I would just like to double the number on those lines only.

I tried doing the following to match a regex and create a matching group but alas it says it says "Pattern not found" but it looks like it should match?

:s/Experience points: (\d+)/\=submatch(1)*2/g

Thanks!

Screenshot

4 Answers 4

3

%s/\(Experience points: \)\@<=\(\d\+\)/\=submatch(2)*2/g

\(...\)@<= is anchoring point

\+ instead of + is used to match more than 1 occurence

1
  • 1
    \zs would probably be easier, since it doesn’t require as much grouping
    – D. Ben Knoble
    Commented May 11 at 17:49
3

Regular expressions? Yuck!

Here's a non-regex version:

Starting from any line with a number on it type:

qqCtrl-ACtrl-XciwCtrl-R=Ctrl-R-*2EnterEscqu

Then run the command:

:g/Experience points:/norm!@q

How it works

  • qq: Start recording a macro into register "q,

  • Ctrl-A: Move to the next number on the line and increment it,

  • Ctrl-X: Decrement it again returning it to it's original value. We only used Ctrl-A as a shortcut for moving to the number,

  • ciw: Change the word under the cursor. i.e. the number,

  • Ctrl-R=: Enter the expression register. This allows you to perform a calculation and enter its result into the buffer,

  • Ctrl-R-: Enter the content of the small-delete register i.e. the number that you are changing,

  • *2: Multiply by two. So if you were on the number 8, now the command line has the contents 8*2,

  • Enter: Perform the calculation. So if your cursor was on the number 8, this will enter 16 into the buffer,

  • Esc: Leave insert mode,

  • q: Stop the recording,

  • u: Undo the change you just made, reverting the buffer to its original state!

Now we have a macro in register "q that will double the first number after the cursor whenever it is run. We can use the :g global command to run this macro on every line that contains the text Experience points:.

1
  • 1
    Super cool! This is certainly easier than fiddling around with regexes.
    – NewUser
    Commented May 13 at 2:22
2

I would do:

:%s/Experience points: \zs(\d\+)/\=submatch(1)*2/g

As already mentioned the pattern not found is because + need to be escaped in Vim

To make sure you not lose the Experience points: we add the \zs to start the replacement after it.

2

Woah, three answers already and not a mention of :g.

Double numbers on all matching lines containing text pattern

Is just a special case of:

Execute <command> on all lines matching <pattern>

which is the job of :help :global:

:g/<pattern>/<command>

In this case:

  • <pattern> would be Experience points (to be refined if needed),
  • and <command> would be s/\d\+/\=submatch(0)*2,

which gives:

:g/Experience points/s/\d\+/\=submatch(0)*2
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.