Any text editor that can apply some math to replacement text?
Solution 1:
After a bit more poking around, it turns out vim can do it with a single command, without scripting. For example, to add 50 to all numbers following <obj param="
you could use:
:%s@<obj param="\(\d\+\)@\='<obj param="' . (submatch(1) + 50)@g
Let me break that down.
:
is the general way to enter/signify command-line mode in vim.
%
means within the scope of the whole document; you could put in a number range, e.g., 1,50
to just do it within the first 50 lines instead.
s
is shorthand for substitute (you can write the whole word out if you prefer)
@
is the delimiter; you could use any other character so long as it's not in what you're searching for. Just use it three times. (The syntax is similar to sed
.)
Everything up to the next occurrence of the delimiter @ is the reg ex pattern to search for, in this case <obj param="
followed by \d\+
, which is any number of digits. The \(
and \)
are there to set this entire sequence of digits as a single reg ex group which would match backreferences like \1
, or vim's submatch
command.
Then the delimiter @
marks that what follows as the replacement text.
The \=
at the beginning here means to substitute the result of some evaluated expression, rather than a reg ex pattern or string, which is key here.
Then we have '<obj param="'
for the start of the replacement text. The .
which follows is vim's function for concatenating strings.
submatch(1)
is a vim built-in function which can be used only within a substitution command, and returns the string which is the same as the regex \1
; you would use submatch(2)
for the equivalent of regex's \2
and so on. (\0
is the whole matched pattern, but we don't want that here.) The \(
and \)
in the search pattern are used to mark off what counts as submatch(1)
.
Hence (submatch(1) + 50)
gives the result of adding 50 to the number which the digits following <obj param="
in the search pattern form.
The delimiter @
is again used to mark off the end of the replacement text.
The flag g
is used to make the substitutions global; you could omit this if you only wanted to replace the first instance on each line.
You can probably work out from there how to add different numbers, or subtract, or divide, etc.
Solution 2:
In Emacs (since version 23): use \,
to execute arbitrary Lisp code in regexp replacement. For example, to square the numbers you could use
M-x replace-regexp
param="\([0-9]+\)"
param="\,(* \#1 \#1)"
In Vim: start your replacement text with \=
(see :help sub-replace-special
). For example, to square the numbers:
s!param="\([0-9]\+\)"!\='param="'.submatch(1)*submatch(1).'"'!
Several editors allow you to do this kind of things with macros: define a macro that 1. looks for the next match and 2. performs the replacement (using an external tool for arithmetic if necessary); repeat the macro as many times as you have matches.
Solution 3:
You can use vim to do that for you. Just open your file and record a macro. Example: Search for any number
/[0-9]{1,}
then press q and a (store macro in register a). After that, press Ctrl-X (increasing the number by 1) and press n (for next search result) afterwards. After you have done that, press q again to save the macro. Now you can apply the macro to the next number by pressing @+a. This will change the current number and jumps to the next one. By repeating that or using x@a, you can repeat that x times.
Well, that description may not be sufficient to show how it can be done. Just refer to a tutorial describing the macro mechanism in vim.