无法通过以制表符结尾的正则表达式捕获子字符串

Can not catch substring by regex which ends with tab

我有两种类型的字符串:

1: ANN=abcdefgh;blabla

2 版本错误:ANN=abcdefgh\tyxz\tyxz

2 实际版本:ANN=abcdefgh

现在我想用正则表达式提取 abcdefgh。所以开始提取总是在"ANN="之后。但结尾是八分号 (;) 或制表符的第一次出现。

这个正则表达式看起来如何?我试过了:

(my @splitUpAnn) = $tabValues[7] =~ /ANN=(.*)[;\t]/;

但我总是得到带分号的版本 1,但它不适用于版本 2...

编辑:要清楚。我没有得到第二版的任何东西。问题不在于使用了最后一个标签!

EDIT2:Ups,输入数据与预期有所不同。要么我在 NOTHING 的末尾有一个分号(参见“2 实际版本”)。对不起!那么正则表达式会是什么呢?

/ANN=(.*?)[;\t]/

制作你的正则表达式non greedy

.* 是贪婪的,将匹配到最后一个 ; or \t 可用。

只需使用尽可能匹配最少的非贪婪量词 *?:

for my $string ('ANN=abcdefgh;blabla', "ANN=abcdefgh\tyxz\tyxz") {
    (my @splitUpAnn) = $string =~ /ANN=(.*?)[;\t]/;
    print "@splitUpAnn\n";
}

如果您想获取第一个分号(如果存在)之前的字符串,或者其他所有内容,只需使用

$string =~ /ANN=([^;]*)/

即捕获除分号以外的所有内容。

使用 .*? 而不是 .*

.*greedy 所以它与第二次出现的 TAB 匹配。

DEMO

my ($ann) = $tabValues[7] =~ /ANN=(.*?)[;\t]/;

前导^否定字符class,因此[^;\t]匹配除;和制表符之外的任何字符。

有多种建议可以让您 .* 非贪婪,但是使用非贪婪作为除优化之外的任何东西都非常脆弱且容易出错。

我已经测试过,我得到了匹配

if ( "ANN=abcdefgh;blabla"  =~ /(ANN=(.*)[;\t])/ ) {
    print ."\n" ;}
if ( "ANN=abcdefgh\tyxz\tyxz"  =~ /(ANN=(.*)[;\t])/ ) {
    print ."\n" ;}

结果是:

ANN=abcdefgh;
ANN=abcdefgh    yxz

所以:

  • 你的要求真的很贪婪,正如之前的回答所述
  • 也许问题在于您将值放入数组的方式,但正则表达式是正确的