为什么我的模式会产生这个结果?我希望它会找到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')]
为什么我的模式会产生这个结果?我希望它会找到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')]
该findall
方法返回匹配列表。如果模式包含捕获组,则每个匹配项都是由模式中每个捕获组匹配的字符串的元组。
从文档中:
pattern
返回in的所有非重叠匹配string
,作为字符串列表。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']
此外,在 re 模块中,除了@rob mayoff 所写的内容之外, * 可能包括该项目的零。
从文档:
*
使生成的 RE 匹配前一个 RE 的 0 个或多个重复,尽可能多的重复。ab* 将匹配 'a'、'ab' 或 'a' 后跟任意数量的 'b'。
我认为您最好的解决方案是制作一个非常简单的正则表达式来捕获 TAA,然后应用一个过滤器来去除 TAA 模式。