如何在表达式中使用Perl的s///?

7 投票
5 回答
664 浏览
提问于 2025-04-15 21:45

我在找这个的时候头都疼了:

我想知道怎么在一个表达式中使用s///,而不是在赋值的时候。为了更清楚我的意思,我想找一个在perl中和python的re.sub(...)相等的用法,特别是在下面这种情况下:

newstring = re.sub('ab', 'cd', oldstring)

到目前为止,我知道在perl中做到这一点的唯一方法是:

$oldstring =~ s/ab/cd/;
$newstring = $oldstring;

注意这里多了一个赋值。

5 个回答

7

Perl中的正则表达式替换总是在原地进行。这意味着你需要把字符串复制到一个新的变量中,然后在这个新变量上进行操作:

(my $newstring = $oldstring) =~ s/ab/cd/;
11

你可以使用 ($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

7

你似乎对 =~ 的工作原理有些误解。=~ 是一个绑定操作符,它把一个变量和正则表达式操作符关联起来。它并不是用来赋值的。

正则表达式操作符默认是作用于一个叫做 $_ 的主题变量,所以 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/;
    }
}

对于我自己的项目,我可能会根据具体问题的需求选择前两个选项中的一个。

撰写回答