正则表达式否定先行断言似乎不起作用

时间:2013-11-14 23:11:44

标签: python regex negative-lookahead

为什么我的模式会产生这种结果?我希望它找到ATG然后是3的序列,不包括TAA

In [102]: s = 'GATGCCTAAG'
In [103]: pat = re.compile("(ATG((\w\w\w)*)(?!TAA))")
In [104]: pat.findall(s)
Out[104]: [('ATGCCTAAG', 'CCTAAG', 'AAG')]

3 个答案:

答案 0 :(得分:3)

findall方法返回匹配列表。如果模式包含捕获组,则每个匹配都是模式中每个捕获组匹配的字符串的元组。

来自the documentation

  

返回patternstring的所有非重叠匹配,作为字符串列表。从左到右扫描string,并按找到的顺序返回匹配项。如果模式中存在一个或多个组,则返回组列表;如果模式有多个组,这将是一个元组列表。结果中包含空匹配,除非它们触及另一场比赛的开头。

您的模式包含三个捕获组。这些组是嵌套的。第一个(也是最外面的)组是整个模式(ATG((\w\w\w)*)(?!TAA))。第二组是((\w\w\w)*)。第三组是(\w\w\w)

请注意,否定前瞻声明(?!TAA) 是捕获组。

实质上,您的模式表示匹配密码子ATG,然后是尽可能多的密码子,但如果匹配将停在TAA密码子,则备份两个密码子。由于*是贪婪的,因此您的模式将匹配中间的TAA密码子。如果TAA出现在输入字符串的末尾,它将仅拒绝TAA密码子(以及之前的密码子)。

由于您的捕获组,您的模式表明每个返回的匹配应包含三个字符串:匹配密码子的完整序列,匹配密码子的序列(不包括初始ATG)和序列中最后匹配的密码子

您可以使用(?:...)将群组标记为非捕获,如下所示:

In [5]: pat = re.compile("(?:ATG(?:(?:\w\w\w)*)(?!TAA))")

如果您的模式不包含捕获组,则findall将每个匹配作为单个字符串返回,而不是作为元组。

In [6]: pat.findall(s)
Out[6]: ['ATGCCTAAG']

如果您想停在第一个 TAA,但如果根本没有TAA,请转到字符串的末尾,您需要检查每个密码子,通过在重复中放置负面的先行断言:

pat = re.compile("ATG(?:(?!TAA)\w\w\w)*")

在初始ATG之后的每个密码子处断言它不应与TAA密码子匹配。

如果你想停在第一个TAA密码子上,即使该密码子与ATG不一致,你也可以这样做:

In [7]: pat = re.compile("ATG(?:(?!.{0,2}TAA)\w\w\w)*")

In [8]: pat.findall(s)
Out[8]: ['ATG']

In [10]: pat.findall('ATGCCTGAATATAAG')
Out[10]: ['ATGCCTGAA']

答案 1 :(得分:0)

此外,在re模块中,*除了@rob mayoff所写的内容之外,*可能包括该项目的零。

来自文档:

*
  

使得到的RE匹配0或更多次重复   在RE之前,尽可能多的重复。 ab *将匹配'a',   'ab'或'a'后跟任意数量的'b'。

答案 2 :(得分:0)

我认为你最好的解决方案是创建一个非常简单的正则表达式来捕获TAA,然后应用一个去除TAA模式的过滤器。