2011-09-02 56 views
2

我有一個這樣的文件:爲什麼takewhile()跳過第一行?

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]第二行,爲什麼呢?

+1

for循環正在吃每塊的第一行 –

回答

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 
+0

嗨@gnibbler,你的代碼可能適用於小文件。我有一個非常大的文件,我不想一次讀完所有文件。但感謝您的代碼。 – gstar2002

+0

@gstar,你爲什麼認爲我的代碼一次讀取整個文件? –

+0

'打開(文件)'而不是'open(「lines.txt」)'.. –

1

我認爲問題在於你正在使用lambda函數lines而不是line。你的預期產出是多少?

1

itertools.takewhile隱式遍歷文件的lines以抓取塊,但for line in lines:也是如此。每次通過循環時,一個line被抓取,扔掉(因爲沒有使用line的代碼),然後再一起編輯block

+0

嗨卡爾,我已經想過了。在第一次taketime()之後,文件指針指向TAB行,在處理完第一個塊之後,「for」將文件指針移動到下一行,'1'並將其提供給takewhile()。它應該是正確的。但是... – gstar2002

+0

for循環不會「移動文件指針」;那是錯誤的思考方式。它遍歷文件的各行。第一次通過循環,'line'等於'1 \ n''。該值已被消耗,並且不再可用於'takewhile()'。 –

+0

好吧,我明白了。所以'code'takewhile()消耗了TAB行。然後'代碼'消費'1 \ n'行,所以'code'takewhile()從'2 \ n'獲取行。大。 – gstar2002

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()解決方案。它更乾淨。

+0

太棒了,我應該嘗試使用你的代碼。謝謝。我不知道,如果正則表達式也可以完成這項工作。 – gstar2002

+1

連續兩行TAB是否會創建一個空白塊? – PaulMcG

+0

@保羅麥圭爾,這是一個非常優秀的觀點。我認爲'itertools.groupby()'答案更清晰並且沒有這個缺陷。 – steveha