如何在表达式中使用Perl的s///?
我在找这个的时候头都疼了:
我想知道怎么在一个表达式中使用s///,而不是在赋值的时候。为了更清楚我的意思,我想找一个在perl中和python的re.sub(...)相等的用法,特别是在下面这种情况下:
newstring = re.sub('ab', 'cd', oldstring)
到目前为止,我知道在perl中做到这一点的唯一方法是:
$oldstring =~ s/ab/cd/;
$newstring = $oldstring;
注意这里多了一个赋值。
5 个回答
Perl中的正则表达式替换总是在原地进行。这意味着你需要把字符串复制到一个新的变量中,然后在这个新变量上进行操作:
(my $newstring = $oldstring) =~ s/ab/cd/;
你可以使用 ($new = $old) =~ s/whatever/whateverelse/;
来实现你想要的功能:
use strict;
my $old = "OLD";
my $new;
($new = $old) =~ s/OLD/NEW/;
print "old=$old, new=$new";
这段代码会产生:
old=OLD, new=NEW
正是你想要的结果
如果你想要一个函数,你可以自己定义一个,这样就不用再赋值了:
use strict;
sub re_sub {
my ($find, $replace, $old) = @_;
my $new = $old;
$new =~ s/$find/$replace/;
return $new;
}
my $old = "ab";
my $new = re_sub('ab', 'cd', $old);
print "new=$new\n";
结果是 new=cd
。
你似乎对 =~
的工作原理有些误解。=~
是一个绑定操作符,它把一个变量和正则表达式操作符关联起来。它并不是用来赋值的。
正则表达式操作符默认是作用于一个叫做 $_
的主题变量,所以 s/foo/bar/;
和 $_ =~ s/foo/bar/;
是一样的。这里并没有发生赋值,主题变量只是被改变了。
对其他变量的操作也是一样的。$var =~ s/foo/bar/;
会把 $var
中第一个出现的 foo
替换成 bar
,同样没有赋值发生。
我给你的最好建议是,写 Python 就用 Python,写 Perl 就用 Perl。不要期待这两种语言是一样的。
你可以像 DVK 建议的那样,写一个子程序来复现你习惯的替换行为。
或者你可以尝试一些地道的 Perl 写法。根据你想在一行中进行多次转换的需求,我提供了一些你可能会觉得有用的例子。
在这里,我用一个 for
循环遍历一个项目,对 $var
进行多次硬编码的转换:
for( $var ) {
s/foo/bar/;
s/fizz/buzz/;
s/whop/bop-a-loo-bop/;
s/parkay/butter/;
s/cow/burger/;
}
或者你可能需要应用一组可变的转换。我定义了一个子程序,循环遍历一个包含旧/新转换对的数组引用列表。这个例子利用了 Perl 的列表参数处理,可以处理任意数量的转换。
my $foo = transform(
'abcd' =>
[ 'a', 'b' ],
[ 'bb', 'c' ],
[ 'cc', 'd' ],
[ 'dd', 'DONE' ],
);
sub transform {
my $var = shift;
for (@_ ) {
my ($old, $new) = @$_;
$var =~ s/$old/$new/;
}
return $var;
}
最后,我稍微调整了一下,提供了一个可以修改第一个参数的转换版本:
my $foo = 'abcd';
transform_in_place(
$foo =>
[ 'a', 'b' ],
[ 'bb', 'c' ],
[ 'cc', 'd' ],
[ 'dd', 'DONE' ],
);
print "$foo\n";
sub transform_in_place {
for my $i (1..$#_ ) {
my ($old, $new) = @{$_[$i]};
$_[0] =~ s/$old/$new/;
}
}
对于我自己的项目,我可能会根据具体问题的需求选择前两个选项中的一个。