Let\'s say I have string \"The quick brown fox jumps over the lazy dog\" can I change this to \"The slow brown fox jumps over the energetic dog\" with one regular expression
The second part of a substitution is a double quoted string, so any normal interpolation can occur. This means you can use the value of the capture to index into a hash:
#!/usr/bin/perl
use strict;
use warnings;
my %replace = (
quick => "slow",
lazy => "energetic",
);
my $regex = join "|", keys %replace;
$regex = qr/$regex/;
my $s = "The quick brown fox jumps over the lazy dog";
$s =~ s/($regex)/$replace{$1}/g;
print "$s\n";
You can do the following.
:%s/quick\(.*\)lazy/slow\1energetic
The trick is to use the parens to match the text between the two words. You can then reference this text in the substitution string by using \1
. You can also use \2
for the second matched paren expression and so on. This allows you to replace multiple words without disturbing the text inbetween.
There's a neat way to do it in Ruby using gsub with a block:
s = "The quick brown fox jumps over the lazy dog"
subs = {'quick' => 'slow', 'lazy' => 'industrious'}
s.gsub(/quick|lazy/) { |match| subs[match] }
# => "The slow brown fox jumps over the industrious dog"
You can concatenate vim substitutions:
The quick brown fox ran quickly next to the lazy brook.
:s/quick/slow/|s/lazy/energetic/
The slow brown fox ran quickly next to the energetic brook.
The advantage here is that you have to type your substitutions just once
Rgds
In perl:
s/quick(.*)lazy/slow${1}energetic/;
In vim:
s/quick\(.*\)lazy/slow\1energetic/;
You can do this in vim using a Dictionary:
:%s/quick\|lazy/\={'quick':'slow','lazy':'energetic'}[submatch(0)]/g
This will change the following text:
The quick brown fox ran quickly next to the lazy brook.
into:
The slow brown fox ran slowly next to the energetic brook.
To see how this works, see :help sub-replace-expression
and :help Dictionary
. In short,
\=
lets you substitute in the result of a vim expression. {'quick':'slow', 'lazy':'energetic'}
is a vim dictionary (like a hash in perl or ruby, or an object in javascript) that uses []
for lookups. submatch(0)
is the matched string This can come in handy when refactoring code - say you want to exchange the variable names for foo
, bar
, and baz
changing
foo
→ bar
bar
→ baz
baz
→ foo
Using a sequence of %s///
commands would be tricky, unless you used temporary variable names - but you'd have to make sure those weren't hitting anything else. Instead, you can use a Dictionary to do it in one pass:
:%s/\<\%(foo\|bar\|baz\)\>/\={'foo':'bar','bar':'baz','baz':'foo'}[submatch(0)]/g
Which changes this code
int foo = 0;
float bar = pow(2.0, (float) foo);
char baz[256] = {};
sprintf(baz,"2^%d = %f\n", foo, bar);
into:
int bar = 0;
float baz = pow(2.0, (float) bar);
char foo[256] = {};
sprintf(foo,"2^%d = %f\n", bar, baz);
If you find yourself doing this a lot, you may want to add the following to your ~/.vimrc
:
" Refactor the given lines using a dictionary
" replacing all occurences of each key in the dictionary with its value
function! Refactor(dict) range
execute a:firstline . ',' . a:lastline . 's/\C\<\%(' . join(keys(a:dict),'\|'). '\)\>/\='.string(a:dict).'[submatch(0)]/ge'
endfunction
command! -range=% -nargs=1 Refactor :<line1>,<line2>call Refactor(<args>)
This lets you use the :Refactor {'frog':'duck', 'duck':'frog'}
command, and is slightly
less repetitive than creating the regex for the dict manually.