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

后端 未结 7 1421
情歌与酒
情歌与酒 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:17

    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";
    
    0 讨论(0)
  • 2020-12-02 16:18

    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.

    0 讨论(0)
  • 2020-12-02 16:22

    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"
    
    0 讨论(0)
  • 2020-12-02 16:29

    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

    0 讨论(0)
  • 2020-12-02 16:29

    In perl:

    s/quick(.*)lazy/slow${1}energetic/;
    

    In vim:

    s/quick\(.*\)lazy/slow\1energetic/;
    
    0 讨论(0)
  • 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 :<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.

    0 讨论(0)
提交回复
热议问题