Regular expression in vim

Tag: vim Author: lxtwins2009 Date: 2009-07-13

How to replace the strings (4000 to 4200 ) to (5000 to 5200) in vim ..

Best Answer

Another possibility:

:%s/\v<4([01]\d{2}|200)>/5\1/g

This one does 200 as well, and it does not suffer from the "leaning toothpick syndrome" too much since it uses the \v switch.

EDIT #1: Added word boundary anchors ('<' and '>') to prevent replacing "14100" etc.


EDIT #2: There are cases where a "word boundary" is not enough to correctly capture the wanted pattern. If you want white space to be the delimiting factor, the expression gets somewhat more complex.

:%s/\v(^|\s)@<=4([01]\d{2}|200)(\s|$)@=/5\1/g

where "(^|\s)@<=" is the look-behind assertion for "start-of-line" or "\s" and "(\s|$)@=" is the look-ahead for "end-of-line" or "\s".

comments:

I think that's the cleanest way since it handles the tricky 4200 case implicitly
this one will work for 4200 aswell

Other Answer1

:%s/\<4\([01][0-9][0-9]\)\>/5\1/g

comments:

will work for all except 4200
Is there a setting so one can enter :s/<4(\[01][0-9][0-9])>/\5\1/g

Other Answer2

:%s/\<4\([0-1][0-9][0-9]\)\>/5\1/g

will do 4000 to 4199. You would have to then do 4200/5200 separately.

A quick explanation. The above finds 4, followed by 0 or 1, followed by 0-9 twice. The 0-1,0-9,0-9 are wrapped in a group, and the replacement (following the slash) says replace with 5 followed by the last matched group (\1, i.e. the bit following the 4).

\< and > are word boundaries, to prevent matching against 14002 (thx Adrian)

% means across all lines. /g means every match on the line (not just the first one).

comments:

How will it work against the number 140002 ?
You are missing a \1, unless I'm mistaken.
Good point. Corrected
@Tomalak - thanks. Typo on my behalf

Other Answer3

If you didn't want to do a full search and replace for some reason, remember that ctrl-a will increment the next number below or after the cursor. So in command mode, you could hit 1000 ctrl-a to increase the next number by 1000.

If you're on Windows, see an answer in this question about how to make ctrl-a increment instead of select all.

Other Answer4

More typing, but less thinking:

:%s/\d\+/\=submatch(0) >= 4000 && submatch(0) <= 4200 ? submatch(0) + 1000 : submatch(0)/g