7

寻找这个我很头疼:你如何在表达式中使用 s/// 而不是赋值。为了澄清我的意思,当在以下上下文中使用时,我正在寻找与 python 的re.sub(...)等效的 perl:

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

到目前为止,我知道如何在 perl 中执行此操作的唯一方法是:

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

注意额外的分配。

4

5 回答 5

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.

于 2010-04-19T01:57:47.560 回答
7

您似乎对如何=~工作有误解。 =~是将变量与正则表达式运算符相关联的绑定运算符。它不做任何任务。

默认情况下,正则表达式运算符都与主题变量一起使用$_,因此s/foo/bar/;与 相同$_ =~ s/foo/bar/;。没有分配发生。主题变量被转换。

对任何其他变量进行操作时,情况类似。通过用 替换第一个实例来进行$var =~ s/foo/bar/;转换。没有分配发生。$varfoobar

我能给你的最好建议是用 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/;
    }
}

对于我自己的项目,我可能会根据特定问题的需要使用前两个选项之一。

于 2010-04-19T07:59:07.573 回答
7

Perl 的正则表达式替换总是“就地”发生。所以需要将字符串复制到一个新变量中,并对新变量进行操作:

(my $newstring = $oldstring) =~ s/ab/cd/;
于 2010-04-19T02:00:32.343 回答
2

你想让 $newstring 成为替换的结果,对吧?

像这样的东西:

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

应该管用。赋值设置$newstring$oldstring,然后评估为$newstring,这是替换作用的内容。

于 2010-04-19T02:02:08.653 回答
1

Based on this, am I right to assume that you cannot have two s/// in one line, one which uses the result of the other, with no intermediate assignments? – mikeY

Yes you are correct. If you want to apply multiple substitutions to the same string I would do

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

The following won't work because s// returns the number of substitutions made, not the changed string.

    $newstring = $oldstring) =~ s/ab/cd/ =~ s/xx/yy/ ;

In summary, Perl's regex operations are very different to Python's and you are better trying to learn what Perl does from scratch rather than trying to map Python concepts onto Perl

于 2010-04-19T08:08:36.207 回答