如何匹配下一行?
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
答案 0 :(得分:2)
$text =~ s/(.*?)(.*)(\s*-\s*$2)/$1$2/;
这个正则表达式有各种各样的问题,但是正确的道路。
使用\2
(或更好:\g2
或\g{-1}
)或其他内容来引用捕获组的内容。执行Perl语句时会插入$2
变量。那时,$2
未定义,因为之前没有匹配。由于未初始化,您会收到警告。即使已定义,也会在编译期间修复模式。
您定义了三个捕获组,但只需要一个。 \K
eep指令有一个技巧:让正则表达式引擎忘记以前匹配的文本,这样它就不会受到替换的影响。也就是说,s/(foo)b/$1/
相当于s/foo\Kb//
。效果类似于可变长度的后视。
(.*?)(.*)
部分是一个回溯的噩梦。我们可以通过添加更多条件来降低您的匹配成本,例如:通过在开始和结束处锚定模式。使用上述修改,我们现在有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 :(得分: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-thingelse
变为somethingelse
。