[英]Can I substitute multiple items in a single regular expression in VIM or Perl?
假设我有一个字符串“快速的棕色狐狸跳过懒狗”我可以用一个正则表达式将其更改为“慢棕狐跳过精力充沛的狗”吗? 目前,我为这种情况使用了两组正则表达式。 (在这种情况下,我使用s/quick/slow/
后跟s/lazy/energetic/
。)
您可以使用词典在vim中执行此操作:
:%s/quick\|lazy/\={'quick':'slow','lazy':'energetic'}[submatch(0)]/g
这将更改以下文本:
快速的棕色狐狸在懒惰的小溪旁边跑得很快 。
成:
缓慢的棕色狐狸跑到旁边的高能小溪慢光年。
要了解其工作原理,请参阅:help sub-replace-expression
和:help Dictionary
。 简而言之,
\\=
允许您替换vim表达式的结果。 {'quick':'slow', 'lazy':'energetic'}
是一个vim字典(如perl或ruby中的哈希,或javascript中的对象),它使用[]
进行查找。 submatch(0)
是匹配的字符串 重构代码时这可以派上用场 - 比如你想要为foo
, bar
和baz
更改变量名称
foo
→ bar
bar
→ baz
baz
→ foo
除非你使用了临时变量名,否则使用%s///
命令序列会很棘手 - 但是你必须确保它们没有碰到任何其他东西。 相反,您可以使用Dictionary在一次传递中执行此操作:
:%s/\<\%(foo\|bar\|baz\)\>/\={'foo':'bar','bar':'baz','baz':'foo'}[submatch(0)]/g
哪个更改此代码
int foo = 0;
float bar = pow(2.0, (float) foo);
char baz[256] = {};
sprintf(baz,"2^%d = %f\n", foo, bar);
成:
int bar = 0;
float baz = pow(2.0, (float) bar);
char foo[256] = {};
sprintf(foo,"2^%d = %f\n", bar, baz);
如果你发现自己做了很多,你可能想要在~/.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>)
这允许你使用:Refactor {'frog':'duck', 'duck':'frog'}
命令,并且比手动创建dict的正则表达式重复性稍差。
替换的第二部分是双引号字符串,因此可以进行任何正常插值。 这意味着您可以使用捕获的值来索引到哈希:
#!/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";
您可以连接vim替换:
快速的棕色狐狸在懒惰的小溪旁边跑得很快。
:s/quick/slow/|s/lazy/energetic/
慢慢的棕色狐狸在精力充沛的小溪旁边迅速奔跑。
这里的优点是你只需输入一次替换
RGDS
您可以执行以下操作。
:%s/quick\(.*\)lazy/slow\1energetic
诀窍是使用parens匹配两个单词之间的文本。 然后,您可以使用\\1
在替换字符串中引用此文本。 您也可以使用\\2
作为第二个匹配的paren表达式,依此类推。 这允许您替换多个单词而不会干扰其间的文本。
在perl中:
s/quick(.*)lazy/slow${1}energetic/;
在vim中:
s/quick\(.*\)lazy/slow\1energetic/;
Chas的答案很好,我唯一提到的另一件事是,如果你正在进行单词交换,你可能想要匹配
\\ B(FOO |酒吧|巴兹| qux)\\ b
避免匹配子串。 如果你进行了大量的单词交换,你可能会开始发现regexps有点限制,并希望做类似的事情:
join '', map { exists $subst{$_} ? $subst{$_} : $_ } split /\b/, $string
使用gsub和块在Ruby中有一个简洁的方法:
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"
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.