我有一个这样的文件:
1
2
3
TAB
1
2
3
TAB
我想将TAB之间的行读作块。
import itertools
def block_generator(file):
with open(file) as lines:
for line in lines:
block = list(itertools.takewhile(lambda x: x.rstrip('\n') != '\t',
lines))
yield block
我想这样使用它:
blocks = block_generator(myfile)
for block in blocks:
do_something(block)
我得到的所有块都以[2,3] [2,3]
之类的第二行开头,为什么?
答案 0 :(得分:4)
这是另一种使用groupby的方法
from itertools import groupby
def block_generator(filename):
with open(filename) as lines:
for pred,block in groupby(lines, "\t\n".__ne__):
if pred:
yield block
答案 1 :(得分:2)
在这里,测试代码。使用while True:
循环,让itertools.takewhile()
使用lines
执行所有操作。当itertools.takewhile()
到达输入的末尾时,它返回一个迭代器,除了引发StopIteration
之外什么都不做,list()
只是变成一个空列表,所以一个简单的if not block:
测试检测到空列表并突破循环。
import itertools
def not_tabline(line):
return '\t' != line.rstrip('\n')
def block_generator(file):
with open(file) as lines:
while True:
block = list(itertools.takewhile(not_tabline, lines))
if not block:
break
yield block
for block in block_generator("test.txt"):
print "BLOCK:"
print block
如下面的评论中所述,这有一个缺陷:如果输入文本在一行中仅包含制表符两行,则此循环将停止处理而不读取所有输入文本。而且我想不出有任何办法可以干净利落地处理这件事。很遗憾,你从itertools.takewhile()
返回的迭代器使用StopIteration
两个作为组末尾的标记,以及你在文件结尾处获得的标记。更糟糕的是,我找不到任何方法来询问文件迭代器对象是否已到达文件结尾。更糟糕的是,itertools.takewhile()
似乎立即将文件迭代器推进到文件结尾;当我尝试使用lines.tell()
重写上述内容以检查我们的进度时,它已经在第一组之后的文件末尾。
我建议使用itertools.groupby()
解决方案。它更干净。
答案 2 :(得分:1)
我认为问题在于你在lambda函数中使用lines
而不是line
。你的预期产量是多少?
答案 3 :(得分:1)
itertools.takewhile
隐式迭代文件的lines
以获取块,但for line in lines:
也是如此。每次循环时,line
都会被抓取,丢弃(因为没有使用line
的代码),然后还有一些block
在一起。