我有一个文本文件,我有一个条件设置,我需要每隔一行提取一大块文本,但文本块可以是任意数量的行(FASTA文件,对于任何生物信息学人员) 。它基本上是这样设置的:
> header, info, info
TEXT-------------------------------------------------------
----------------------------------------------------
>header, info...
TEXT-----------------------------------------------------
......等等。
我正在尝试提取“TEXT”部分。这是我设置的代码:
for line in ffile:
if line.startswith('>'):
# do stuff to header line
try:
sequence = ""
seqcheck = ffile.next() # line after the header will always be the beginning of TEXT
while not seqcheck.startswith('>'):
sequence += seqcheck
seqcheck = ffile.next()
except: # iteration error check
break
这不起作用,因为每次调用next()时,它都会继续for循环,这会导致我跳过很多行并丢失大量数据。如何在没有向前移动迭代器的情况下“窥视”下一行?
答案 0 :(得分:3)
我想如果你检查数据不是以'>'
开头会更容易。
>>> content = '''> header, info, info
... TEXT-------------------------------------------------------
... ----------------------------------------------------
... >header, info...
... TEXT-----------------------------------------------------'''
>>>
>>> f = StringIO(content)
>>>
>>> my_data = []
>>> for line in f:
... if not line.startswith('>'):
... my_data.append(line)
...
>>> ''.join(my_data)
'TEXT-------------------------------------------------------\n----------------------------------------------------\nTEXT-----------------------------------------------------'
>>>
@tobias_k这应该分开行:
>>> def get_content(f):
... my_data = []
... for line in f:
... if line.startswith('>'):
... yield my_data
... my_data = []
... else:
... my_data.append(line)
... yield my_data # the last on
...
>>>
>>> f.seek(0)
>>> for i in get_content(f):
... print i
...
[]
['TEXT-------------------------------------------------------\n', '----------------------------------------------------\n']
['TEXT-----------------------------------------------------']
>>>
答案 1 :(得分:1)
您是否考虑过正则表达式?:
txt='''\
> header, info, info
TEXT----------------------------------------------------------------
TEXT2-------------------------------------------
>header, info...
TEXT-----------------------------------------------------'''
import re
for header, data in ((m.group(1), m.group(2)) for m in re.finditer(r'^(?:(>.*?$)(.*?)(?=^>|\Z))', txt, re.S | re.M)):
# process header
# process data
print header, data
这将为您提供元组中该标题的标题和数据,以执行您需要执行的操作。
如果您的文件很大,请you can use mmap以避免将整个文件读入内存。
答案 2 :(得分:0)
这是另一种方法。与我上面的注释相反,这个 使用嵌套循环来收集属于一个文本块的所有行(所以这个逻辑不是那么分散),但是这样做的方式略有不同: / p>
for line in ffile:
if not line.startswith('>'):
sequence = line
for line in ffile:
if line.startswith('>'): break
sequence += line
print "<text>", sequence
if line.startswith('>'):
print "<header>", line
首先,它使用第二个for
循环(使用与外循环完全相同的ffile
迭代器),因此不需要try/except
。其次,没有行丢失,因为我们将当前line
提供给sequence
,并且因为我们首先执行非标头案例:在达到第二次if
检查时, line
变量将保留嵌套循环停止的标题行(此处不使用else
,否则这将无效。)
答案 3 :(得分:0)
我对偷看的建议是使用列表和enumerate
:
lines = ffile.readlines()
for i, line in enumerate(lines):
if line.startswith('>'):
sequence = ""
for l in lines[i+1:]:
if l.startswith('>'):
break
sequence += l
答案 4 :(得分:0)
这是一种对原始代码进行很少更改的方法。这取决于你的情况,但有时你做你想做的事情更容易,而不必担心重新组织/重构其他一切!如果你想推送一些东西,那么它会再次被迭代,然后就这样做就可以了!
这里我们实例化一个deque()对象,它保存先前读取的行。然后我们包装ffile迭代器,它在从ffile获取新行之前对对象进行简单检查并排除其中的条目。
因此,每当我们阅读需要在其他地方重新处理的内容时,请将其附加到deque对象并突破。
import cStringIO,collections
original_ffile=cStringIO.StringIO('''
> header, info, info
TEXT----------------------------------------------------------------
TEXT2-------------------------------------------
>header, info...
TEXT-----------------------------------------------------''')
def peaker(_iter,_buffer):
popleft=_buffer.popleft
while True:
while _buffer: yield popleft() # this implements FIFO-style
yield next(_iter) # we don't have to catch StopIteration here!
buf=collections.deque()
push_back=buf.append
ffile=peaker(original_ffile,buf)
for line in ffile:
if line.startswith('>'):
print "found a header! %s"%line[:-1]
# do stuff to header line
sequence = ""
for seqcheck in ffile:
if seqcheck.startswith('>'):
print "oops, we've gone too far, pushing back: %s"%seqcheck[:-1]
push_back(seqcheck)
break
sequence += seqcheck
输出:
found a header! > header, info, info
oops, we've gone too far, pushing back: >header, info...
found a header! >header, info...