昨天,我写了第一个答案。
然后我阅读了 ATOzTOA 的答案,其中他有一个非常好的主意:使用积极的后视断言。
我认为我的答案完全出局了,他的想法是正确的做法。
但后来,我意识到 ATOzTOA 的代码存在缺陷。
假设检查字符串中有一部分'ATGxzyxyzyyxyATGxzxzyxyzxxzzxzyzyxyzTGA'
:肯定匹配将发生在'xzyxyzyyxyATGxzxzyxyzxxzzxzyzyxyzTGA'
前面,断言匹配发生在前面'ATG'
,因此该部分将构成匹配;没关系。
但这意味着在此匹配之后,正则表达式电机位于该部分的末尾 'xzyxyzyyxyATGxzxzyxyzxxzzxzyzyxyzTGA'
。
因此,当正则表达式电机将搜索下一个匹配项时,它不会'ATG'
在此部分的当前位置找到匹配项,因为它会从很久之后的位置再次运行。
.
因此,实现问题所需的唯一方法实际上是我编写的第一个算法,然后我重新发布它。
该工作由函数find_ORF_seq()完成
如果您将True
作为第二个参数传递给messages
函数的第二个参数find_ORF_seq()
,它将打印有助于理解算法的消息。
如果不是,则参数messages
采用默认值None
该模式是'(atg).+?(?:TAA|TGA|TAG)'
用一些大写字母和其他小写字母书写的,但这并不是相对于大写字母和小写字母正确捕捉部分的原因。因为,正如您将看到的那样,re.IGNORECASE
使用了标志:这个标志是必要的,因为匹配的部分(?:TAA|TGA|TAG)
可以落在小写部分和大写部分。
该算法的本质在于while循环,这是必要的,因为正如我上面解释的那样,研究的部分可能会重叠(据我理解正确并且您给出的示例和解释是正确的)。
所以不可能使用findall()
orfinditer()
并且我做了一个循环。
为了避免在fdna序列中逐个碱基地进行迭代,我使用了在字符串ma.start()
中给出匹配开始位置的方法ma
,并且我增加了s
with s = s + p + 1
( +1的值以不再开始搜索找到匹配的开始!)
我的算法不需要以下信息,start_positions
因为我不使用后视断言,而是对前 3 个字母进行真正匹配:当匹配开始位于大写部分时,匹配被声明为不符合约束,即它说什么时候ma.group(1)
捕获前三个碱基(可以是'ATG'
或者'atg'
因为正则表达式忽略大小写)等于'ATG'
我不得不s = s + p + 1
代替,s = s + p + 3
因为您搜索的部分似乎没有被三个碱基的倍数隔开。
import re
sequence_list = ['atgttttgatgATGTTTTGATTT',
'atggggtagatggggATGGGGTGA',
'atgaaataatggggATGAAATAA',
'aaggtacttctcggctaACTTTTTCCAAGT']
pat = '(atg).+?(?:TAA|TGA|TAG)'
reg = re.compile(pat,re.IGNORECASE)
def find_ORF_seq(fdna,messages=None,s=0,reg=reg):
ORF_sequences = []
if messages:
print 's before == ',s
while True:
if messages:
print ('---------------------------\n'
's == %d\n'
'fdna[%d:] == %r' % (s,s,fdna[s:]))
ma = reg.search(fdna[s:])
if messages:
print 'reg.search(fdna[%d:]) == %r' % (s,ma)
if ma:
if messages:
print ('ma.group() == %r\n'
'ma.group(1) == %r'
% (ma.group(),ma.group(1)))
if ma.group(1)=='ATG':
if messages:
print "ma.group(1) is uppercased 'ATG' then I break"
break
else:
ORF_sequences.append(ma.group().upper())
p = ma.start()
if messages:
print (' The match is at position p == %d in fdna[%d:]\n'
' and at position s + p == %d + %d == %d in fdna\n'
' then I put s = s + p + 1 == %d'
% (p,s, s,p,s+p, s+p+1))
s = s + p + 1
else:
break
if messages:
print '\n==== RESULT ======\n'
return ORF_sequences
for fdna in sequence_list:
print ('\n============================================')
print ('fdna == %s\n'
'ORF_sequences == %r'
% (fdna, find_ORF_seq(fdna,True)))
###############################
print '\n\n\n######################\n\ninput sample'
fdna = 'atgttttgatggATGTTTGATTTATTTTAG'
print ' fdna == %s' % fdna
print ' **atgttttga**tggATGTTTGATTTATTTTAG'
print ' atgttttg**atggATGTTTGA**TTTATTTTAG'
print 'output sample'
print " ORF_sequences = ['ATGTTTTGA','ATGGATGTTTGA']"
print '\nfind_ORF_seq(fdna) ==',find_ORF_seq(fdna)
.
相同的功能不用print
说明更好看算法。
import re
pat = '(atg).+?(?:TAA|TGA|TAG)'
reg = re.compile(pat,re.IGNORECASE)
def find_ORF_seq(fdna,messages=None,s =0,reg=reg):
ORF_sequences = []
while True:
ma = reg.search(fdna[s:])
if ma:
if ma.group(1)=='ATG':
break
else:
ORF_sequences.append(ma.group().upper())
s = s + ma.start() + 1
else:
break
return ORF_sequences
.
我比较了 ATOzTOA 的和我的这两个函数,并用fdna序列揭示了这个缺陷。这使我所描述的合法化。
from find_ORF_sequences import find_ORF_seq
from ATOz_get_sequences import getSequences
fdna = 'atgggatggtagatggatgggATGGGGTGA'
print 'fdna == %s' % fdna
print 'find_ORF_seq(fdna)\n',find_ORF_seq(fdna)
print 'getSequences(fdna)\n',getSequences(fdna)
结果
fdna == atgggatggtagatggatgggATGGGGTGA
find_ORF_seq(fdna)
['ATGGGATGGTAG', 'ATGGTAG', 'ATGGATGGGATGGGGTGA', 'ATGGGATGGGGTGA']
getSequences(fdna)
['ATGGGATGGTAG', 'ATGGATGGGATGGGGTGA']
.
但毕竟,也许,我想知道....:
你想要另一个匹配的内部部分的匹配,比如'ATGGGATGGGGTGA'
在末尾'ATGGATGGGATGGGGTGA'
吗?
如果不是,ATOzTOA 的答案也适合。