1

如何匹配下一行?

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

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

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

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

  2. 您定义了三个捕获组,但只需要一个。eep 指令有一个技巧\K:它让正则表达式引擎忘记之前匹配的文本,这样它就不会受到替换的影响。即,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$/;
于 2013-07-01T19:43:54.167 回答
1

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

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

请注意,当替换零件被评估,$1并且$2已经被设置并且可以按预期进行插值时。您还可以使用以下方法使模式更简洁(并且可能更有效):

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

.*?如果初始部分 ( ) 是任意的,则无需匹配初始部分,并且无论如何您只需将其写回即可。您可能想要做的是将模式锚定到字符串的末尾:

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

否则(通过您或我的初始尝试),您将something-thingelse变成somethingelse.

于 2013-07-01T19:40:46.507 回答