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

后端 未结 7 1452
情歌与酒
情歌与酒 2020-12-02 15:57

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

7条回答
  •  甜味超标
    2020-12-02 16:32

    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\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 :,call Refactor()
    

    This lets you use the :Refactor {'frog':'duck', 'duck':'frog'} command, and is slightly less repetitive than creating the regex for the dict manually.

提交回复
热议问题