Perl字符串替换不适用于$ 1和$ 2

时间:2019-06-17 20:26:21

标签: regex perl replace

当我使用前面定义的$ 1和$ 2时,搜索和替换不起作用。

当我将其存储在新变量中时,它将起作用。

不能按预期工作。

perl -e'
   my $name = "start middle end";
   my $rep = "";
   my $orig = "";
   if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
      $orig = $1;
      $rep = $2;
      $name =~ s/$1/$2/;
      print "$name\n";
   }
'
sta middle end

是因为$ 1和$ 2被替换为新的$ name =〜我在做什么吗?

按预期工作。

perl -e'
   my $name = "start middle end";
   my $rep = "";
   my $orig = "";
   if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
      $orig = $1;
      $rep = $2;
      $name =~ s/$orig/${rep}/;
      print "$name\n";
   }
'
staend middle end

是否有更好的班轮来做到这一点?我不想定义新变量。

6 个答案:

答案 0 :(得分:4)

是的,新的成功正则表达式匹配替换了$1$2

您可以完全避免全局变量,如下所示:

perl -e'
   my $name = "start middle end";
   if ( my ($orig, $rep) = $name =~ /sta(.*?)\s\w+\s(.*)/ ) {
      $name =~ s/\Q$orig/$rep/;
      CORE::say $name;
   }
'

更好的是,您可以避免进行以下两次匹配:

perl -e'
   my $name = "start middle end";
   if ( $name =~ s/sta\K.*?(?=\s\w+\s(.*))/$1/ ) {
      CORE::say $name;
   }
'

但是,我将使用以下内容:

perl -e'
   my $name = "start middle end";
   if ( (my ($prefix, $suffix, $foo) = $name =~ /^(.*?sta).*?(\s\w+\s(.*))/ ) {
      CORE::say "$prefix$foo$suffix";
   }
'

请注意,您的代码遇到了code injection错误,我已使用quotemeta(如\Q)对其进行了修复。

答案 1 :(得分:2)

通过在s ///运算符的第一部分中运行匹配项来重置捕获变量,以供替换使用。列表上下文中的m //运算符将返回捕获的值,因此您可以在此处轻松分配它们。另外,如果您的搜索字符串不是正则表达式,则可能要使用\ Q(quotemeta)。

perl -e'
   my $name = "start middle end";
   if (my ($orig, $rep) = $name =~ /sta(.*?)\s\w+\s(.*)/) {
      $name =~ s/\Q$orig/$rep/;
      print "$name\n";
   }
'
sta middle end

答案 2 :(得分:1)

在这里,以防万一,我们会有意外的多余空间,我们也可以尝试以下表达式:

(sta)([a-z]*)\s+(\w+)\s+(.+)

这只是另一种选择。

测试

perl -e'
    my $name = "start       middle    end";
    $name =~ s/(sta)([a-z]*)\s+(\w+)\s+(.+)/$1$4 $3 $4/;
    print "$name\n";
    '

输出

staend middle end

Please see the demo here

答案 3 :(得分:0)

替换部分中的

$2指的是同一替换的图案部分中的捕获组。因此,您只需要一个变量即可记住$ 2。

perl -lwe '$_ = "start middle end" ; if (/sta(.*?)\s\w+\s(.*)/) {my $rep = $2; s/$1/$rep/; print}'
staend middle end

答案 4 :(得分:0)

您可以通过使用最后一个匹配的开始和结束全局数组@-@+并仅执行子字符串替换来避免其他变量:

my $name = "start middle end";
if ($name =~ /sta(.*?)\s\w+\s(.*)/) {
    substr($name, $-[1], $+[1]-$-[1], $2);
    print "$name\n";
}

perldoc perlvar中查看@-的条目

答案 5 :(得分:0)

regex捕获变量根据代码表现出奇怪的行为
流,函数调用和其他内容。
要对此进行全面的解释和说明,需要几页
的解释。

就目前而言,避免整个混乱,只需使用一个正则表达式

 perl -e'
    my $name = "start middle end";
    $name =~ s/^(sta)(.*?)(\s\w+\s)(.*)/$1$4$3$4/;
    print "$name\n";
 '