0

当正则表达式保存在变量中时,谁能解释正则表达式文本替换?我正在尝试处理一些文本,实际上是 Clearcase 配置规范,并随时替换文本。替换规则保存在哈希数组中,其中包含要匹配的正则表达式和要替换的文本。

输入文本看起来像这样:

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

大多数替换只是删除包含特定文本字符串的行,这很好用。在某些情况下,我想替换文本,但重新使用 VERSION_STRING 文本。我尝试在替换表达式中使用 $1 ,但它不起作用。$1 获取匹配中的版本字符串,但 $1 的替换在替换中不起作用。

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

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

IE。一行输入变成了两个输出,并且版本字符串已被重用。

代码看起来像这样。首先是正则表达式和替换:

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" }

                );

在第二个正则表达式中,变量 $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";
                }
         }
}

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

4

2 回答 2

3

正则表达式中的替换字符串只被评估一次,它转换$hash->{subs}成它的字符串。您需要再次评估它以插入其内部变量。您可以将e修饰符添加到正则表达式的末尾,它告诉 Perl 运行替换,通过eval它可以执行第二次插值等。您可以应用多个e标志来多次评估(如果您有需要它的问题)。正如tchrist 有用地指出的那样,在这种情况下,您需要,ee因为第一个 eval 只会扩展变量,第二个需要扩展扩展中的变量。

perlop您可以在关于s运算符中找到更多详细信息。

于 2010-11-03T17:36:58.637 回答
2

替换表达式没有编译。所以你唯一能做的就是用e标志执行或评估它:

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

\\1更改为\$1替换字符串后为我工作。

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

仅将匹配的部分替换为作为完整替换存储的文字值。为了使替换工作,您必须强制 Perl 将字符串评估为 string,这意味着您甚至必须重新添加 dquotes 才能获得您正在寻找的插值行为(因为它们不是一部分的字符串。)$hash->{subs}

但这有点笨拙,所以我将替换表达式更改为 subs:

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使它更防弹,因为你不依赖于 global $1

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

当然,您可以像这样更改 sub:

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

最后一点:"\.\.\."没有做你认为的那样。你刚刚'...'在正则表达式中结束,它匹配任何三个字符。

于 2010-11-03T17:39:21.640 回答