代码之家  ›  专栏  ›  技术社区  ›  0xDEADBEEF

Perl正则表达式变量与匹配模式替换

  •  0
  • 0xDEADBEEF  · 技术社区  · 14 年前

    当正则表达式保存在变量中时,有人能解释正则表达式文本替换吗?我正在尝试处理一些文本,实际上是Clearcase配置规范,并在我进行时替换文本。替换规则保存在一个散列数组中,这些散列包含要匹配的正则表达式和要替换的文本。

    输入文本看起来像这样:

    element  /my_elem/releases/...  VERSION_STRING.020 -nocheckout
    

    在这些情况下,输出应该如下所示:

    element  -directory  /my_elem/releases/... VERSION_STRING.020 -nocheckout
    element  /my_elem/releases/.../*.[ch]  VERSION_STRING.020 -nocheckout
    

    即一行输入变为两个输出,版本字符串已被重新使用。

    my @Special_Regex = (   
                      { regex => "\\s*element\\s*\/my_elem_removed\\s*\/main\/\\d+\$",                  subs => "# Line removed" },
                      { regex => "\\s*element\\s*\/my_elem_changed\/releases\/\.\.\.\\s*\(\.\*\$\)", 
                        subs => "element  \-directory  \/my_elem\/releases\/\.\.\. \\1\nelement  \/my_elem\/releases\/\.\.\.\/\*\.\[ch\]  \\1" }
    
                    );
    

    在第二个regex中,变量$1在部分(.*\$)中定义,并且它工作正常。但是,subs表达式不能替代它。

     foreach my $line (<INFILE>)
            {
            chomp($line);
            my $test = $line;
            foreach my $hash (@Special_Regex)
            {
                my $regex = qr/$hash->{regex}/is;
                if($test =~ s/$regex/$hash->{subs}/)
                    {
                    print "$test\n";
                    print "$line\n";
                    print "$1\n";
                    }
             }
    }
    

    我错过了什么?提前谢谢。

    2 回复  |  直到 14 年前
        1
  •  2
  •   Axeman maxelost    14 年前

    没有替换表达式的编译。所以你唯一能做的就是用 e

    if($test =~ s/$regex/eval qq["$hash->{subs}"]/e ) { #...
    

    换车后为我工作 \\1 \$1 在替换字符串中。

    s/$regex/$hash->{subs}/
    

    字面意义的 $hash->{subs} 作为 完全替代。为了使替换生效,必须强制Perl计算字符串 作为一根弦 ,因此,这意味着您甚至必须将dquotes添加回原来的位置,以便获得您要查找的插值行为(因为它们不是字符串的一部分)

    my @Special_Regex 
        = ( 
            { regex => qr{\s*element\s+/my_elem_removed\s*/main/\d+$}
            , subs  => sub { '#Line removed' }
            }
        ,   { regex => qr{\s*element\s+/my_elem_changed/releases/\.\.\.\s*(.*$)}
            , subs  => sub { 
                return "element  -directory  /my_elem/releases/... $1\n"
                     . "element  /my_elem/releases/.../*.[ch]  $1"
                     ; 
              }
            }
    
        );
    

    我去掉了一堆你不用在替换表达式中逃避的东西。因为你想做的是插值 $1 在替换字符串中,子例程 简单地 那。因为 1美元 在匹配其他内容之前是可见的,运行此代码时它将是正确的值。

    所以现在替换品看起来是:

    s/$regex/$hash->{subs}->()/e
    

    当然可以了 通过 使它更加防弹,因为你不依赖全球 1美元 :

    s/$regex/$hash->{subs}->( $1 )/e
    

    当然,你可以把潜艇改成这样:

    subs => sub {
        my $c1 = shift;
        return "element  -directory  /my_elem/releases/... $c1\n"
             . "element  /my_elem/releases/.../*.[ch]  $c1"
             ; 
    }
    

    "\.\.\." 不是你想的那样。你刚刚结束了 '...' 在regex中,它匹配任意三个字符。

        2
  •  3
  •   daxim e.dan    14 年前

    $hash->{subs} 在它的弦里。你需要再次计算它来插值它的内部变量。您可以添加 e eval 它可以执行第二次插值。可以应用多个 e类 要多次求值的标志(如果有需要的问题)。作为 有帮助地指出,在这种情况下,您需要 ee 因为第一个eval只会扩展变量,所以第二个eval需要在扩展中扩展变量。

    你可以在 perlop about the s operator