Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
521 views
in Technique[技术] by (71.8m points)

regex - Can I substitute multiple items in a single regular expression in VIM or Perl?

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? Currently, I use two sets of regular expressions for this situation. (In this case, I use s/quick/slow/ followed by s/lazy/energetic/.)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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

  • foobar
  • barbaz
  • bazfoo

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
", foo, bar);

into:

int bar = 0;
float baz = pow(2.0, (float) bar);
char foo[256] = {};

sprintf(foo,"2^%d = %f
", 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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...