2013-07-01 74 views
1

如何匹配下一行?Perl正则表达式与LHS组合

sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

想要从最后删除- repetative.text,但只有当它重复。

sometext_TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

我试图

use strictures; 
my $text="sometext_TEXT1.xxx-TEXT1.xxx"; 
$text =~ s/(.*?)(.*)(\s*-\s*$2)/$1$2/; 
print "$text\n"; 

打印

Use of uninitialized value $2 in regexp compilation at a line 3. 

与其他词,寻找下一个split + match更好的解决方案...

while(<DATA>) { 
     chomp; 

     my($first, $second) = split /\s*-\s*/; 
     s/\s*-\s*$second$// if ($first =~ /$second$/); 

     print "$_\n"; 
} 
__DATA__ 
sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 
+4

在替代的匹配部分反向引用必须\ 2而不是$ 2 – user1937198

回答

2
$text =~ s/(.*?)(.*)(\s*-\s*$2)/$1$2/; 

这个正则表达式有不同的问题,但在正确的道路上。

  1. 使用\2(或更好:\g2\g{-1})或东西来引用捕获组的内容。在执行Perl语句时插入$2变量。那时,$2是未定义的,因为之前没有匹配。由于未初始化,您会收到警告。即使它被定义,模式在编译期间也会被修复。

  2. 你定义了三个捕获组,但只需要一个。有一个与\K EEP指令一招:它让我们的正则表达式引擎忘记先前匹配的文本,所以它不会被替代的影响。也就是说,s/(foo)b/$1/相当于s/foo\Kb//。效果类似于可变长度lookbehind。

  3. (.*?)(.*)的部分是一个位的回溯梦魇。我们可以通过添加更多条件来降低您的匹配成本。通过锚定模式开始和结束的行。使用上述修改,我们现在有s/^.*?(.*)\K\s*-\s*\g1$//。但转念一想,我们可以只取出^.*?因为这说明什么正则表达式引擎做呢!

一个简短的测试:

while(<DATA>) { 
    s/(.*)\K\s*-\s*\g1$//; 
    print; 
} 
__DATA__ 
sometext_TEXT1.yyy-TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

输出:

sometext_TEXT1.yyy 
anothertext_OTHER.yyy-MAX.yyy 

的几句话对您split亭解决方案:这也将缩短线路

sometext_TEXT1xyyy - 1.xyyy 

因为当你插入一个变量到一个正则表达式中时,内容不会逐字匹配。相反,它们被解释为一种模式(其中.与任何非新行代码点匹配)!您可以通过引用所有的元字符与\Q...\E逃生避免这种情况:

s/\s*-\s*\Q$second\E$// if $first =~ /\Q$second\E$/; 
1

当您使用$2 Perl将尝试插入该变量,但该变量只会在匹配完成后设置为。你想要的,什么是反向引用,为此,你需要使用\2

$text =~ s/(.*?)(.*)(\s*-\s*\2)/$1$2/; 

需要注意的是,当更换部件进行评估,$1$2已定,预期可以插值。你也可以将图案多一点简洁(而且可能更有效),使用:

$text =~ s/(.*)\s*-\s*\2/$1/; 

没有必要的初始部分(.*?)相匹配,如果是任意的,你只是把它写回无妨。你可能希望做虽然是锚定模式字符串的结尾:

$text =~ s/(.*)\s*-\s*\1$/$1/; 

否则(你的初次尝试或地雷),你会转something-thingelsesomethingelse

+0

最后的正则表达式应该是'$文字=〜S /(。 *)\ s * - \ s * \ 1 $/$ 1 /;'...... :) – jm666

+0

@ jm666当然!谢谢!修正 –