你能解释一下为什么我的Perl正则表达式模式中的G表现如此吗?

时间:2013-08-19 09:37:09

标签: regex perl

$dna = "ATCGTTGAATGCAAATGACATGAC";
while ($dna =~ /(\w\w\w)*?TGA/g) {  # note the minimal *?        
    print "Got a TGA stop codon at position ", pos $dna, "\n";
}

答案是:

Got a TGA stop codon at position 18    
Got a TGA stop codon at position 23

为什么位置18,但不是8?以下23.我很困惑它是如何匹配的?关于比赛的详细信息是什么?

但正确的代码是:

while ($dna =~ /\G(\w\w\w)*?TGA/g) {        
  print "Got a TGA stop codon at position ", pos $dna, "\n";
}

打印:

Got a TGA stop codon at position 18

如何?

3 个答案:

答案 0 :(得分:6)

正如@Tomalak所说,你不需要*?,因为这是你情况混乱的原因。以下是您的第一段代码中的内容:

它看到(\w\w\w)*?不情愿(可选)所以它跳过它并尝试匹配TGA但没有运气因此引擎回溯并匹配三个连续的单词字符阅读ATC,现在再次尝试匹配TGA但又没有运气,因此它连续三次读取\w并且引擎到目前为止已读取ATCGTT

现在它再次尝试TGA并且没有运气,然后再次回溯并再次阅读\w\w\w,现在它已经ATCGTTGAA,现在尝试查找TGA但它已经在读取最后三个\w时跳过第一个,因此这就是引擎无法找到第一个TGA因此无法报告其位置的原因。

现在引擎继续这件事,直到它找到TGA 之后的AAA(如果你像我一样继续前进,你会看到这是怎么回事) ,现在它执行循环打印18内的指令。

由于您已使用/g修饰符,下一次匹配尝试将从第一个匹配尝试开始并失败,然后在最后一个匹配后尝试另一个匹配跳过单个字符,依此类推,直到匹配最后TGA并打印23。

那么为什么在第二种情况下它只匹配18处的一个位置,使用\G修饰符的效果是什么?

一切都一样,直到找到第一个匹配,就像前三个AAA之后的情况一样,然后当下一个匹配开始时,它尝试匹配\G,这意味着尝试匹配最后一个匹配在AAATGA之后结束并且它起作用,然后它尝试匹配字符串的其余部分但是失败,但是这次当引擎试图跳过一个或两个或三个左右时,它总是会尝试首先匹配\G,除非匹配是在上一个结束时开始的(即AAATGA之后)所以它会一直失败,因此只报告一个18岁的单场比赛。

只需删除*? @Tomalak说。

答案 1 :(得分:1)

您根本不需要使用*?

$dna = "ATCGTTGAATGCAAATGACATGAC";
while ($dna =~ /(?:\w\w\w)TGA/g) {
    print "Got a TGA stop codon at position ", pos $dna, "\n";3.    
}

打印

Got a TGA stop codon at position 8
Got a TGA stop codon at position 18

请注意*?使前面的原子可选,但实际上你希望它是必需的。

  • 非捕获组(?:...)不是必需的。您可以使用普通组。
  • 另一个变体是/[TGAC]{3}TGA/g

答案 2 :(得分:0)

  

在第18位获得TGA终止密码子

第一场比赛是在第18位而非第8场的原因是因为第18位的比赛是最左侧比赛:

 (ATC) (GTT) (GAA) (TGC) (AAA) [TGA] CATGAC
  0     3     6     9     12    15   18

此匹配发生在零开始位置,在TGA之前可以匹配(\ w \ w \ w)5次。

但是导致pos 8的匹配发生在2的起始位置,它可以在TGA之前匹配(\ w \ w \ w)一次:

  AT (CGT) [TGA] ATGCAAATGACATGAC
      2     5    8

正则表达式更喜欢最左侧匹配。

添加\G需要在开始时(或在您的上一场比赛之后)锚定匹配。在这种情况下,只有当TGA是字符串开头的3个字符的倍数时才会匹配TGA。这是你需要的吗?