2012-11-30 19 views
5

Python業餘愛好者在這裏。我有一個文本文件列出了數千行的信息,我試圖根據它們是否匹配一個模式來選擇一行和下面的2-3行。 我過濾的文件下來,從原來的只包含感興趣的文件的部分給我,讓我現在的文件看起來像這樣:選擇多行txt文檔並在python中寫入新文本文檔的問題

trig1.RESP: 
stim4: silence.wav 
trig1.RESP: 
trig6.RESP: 1 
trig1.RESP: 
trig1.RESP: 
trig5.RESP: 1 
stim5: silence.wav 
trig1.RESP: 
trig6.RESP: 1 
stim3: silence.wav 
trig1.RESP: 
stim5: silence.wav 
trig1.RESP: 
trig6.RESP: 1 

等等等等... 基本上什麼我試圖做的是編寫每一行,其中包含該行的silence.wav部分,然後是後面的兩行。我用下面的代碼:

parsed_output = open("name-of-file-to-be-written", "w") 
filtered_input = open("name-of-file-that-has-above-data", "r") 
for line in filtered_input: 
    if "silence.wav" in line and "trig1" in filtered_input.next(): 
     parsed_output.write(line) 
     parsed_output.write(filtered_input.next()) 
parsed_output.close() 

也能正常工作的大部分,因爲它打印silence.wav線,並且具有響應(我最感興趣的部分,一個響應之前TRIG1行在這一點上不那麼重要)。不過我碰到的問題是,當走行:

stim3: silence.wav 
trig1.RESP: 
stim5: silence.wav 

由於我的輸出,那麼會寫(跳過TRIG1後下一行)的stim3(當前行)和stim5,我認爲它移動到下一個「stim:silence.wav」並跳過了stim5,因爲它在寫入之前包含在前一個命令中。 我想在trig5之後使用trig6.RESP:1,但是由於我描述的原因,我的輸出沒有顯示它。 有沒有一種方法可以讓它不跳過那個stim5?

對不起,如果這真的很長。先謝謝你!

+0

小旁註:我建議你總是關閉你打開的文件。最好的方法 - 使用'with'語句。 – cleg

回答

4

這樣的事情呢? (完全未經測試

count = 3 
for line in filtered_input: 
    if "silence.wav" in line: 
     count = 0 
    else: 
     count += 1 

    if count <= 2: 
     filtered_output.write(line) 

這不是幻想,但我認爲它應該是相當強勁。

+0

哦,我的天啊,那麼簡單。它也工作!謝謝你,謝謝你,謝謝你! – user1867442

1

一種可能的方法是使用一個deque,讓您可以在同一時間跟蹤的三條線:

import collections 

parsed_output = open("name-of-file-to-be-written", "w") 
filtered_input = open("name-of-file-that-has-above-data", "r") 

window = collections.deque([None]*3, maxlen=3) 
for line in filtered_input: 
    window.append(line) 
    if 'silence.wav' in window[0]: 
     parsed_output.write(window[0]) 
     # only output next two lines if they don't also contain 'silence.wav' 
     if 'silence.wav' not in window[1]: 
      parsed_output.write(window[1]) 
      if 'silence.wav' not in window[2]: 
       parsed_output.write(window[2]) 
# following if/elif in case last or second to last line contain 'silence.wav' 
if 'silence.wav' in window[1]: 
    parsed_output.write(window[1]) 
    parsed_output.write(window[2]) 
elif 'silence.wav' in window[2]: 
    parsed_output.write(window[2]) 
parsed_output.close() 

如果您提供maxlen參數雙端隊列,那麼當您添加其他元素,以一個結束一個元素被彈出的另一端,例如:

>>> x = collections.deque([1, 2, 3], maxlen=3) 
>>> x 
deque([1, 2, 3], maxlen=3) 
>>> x.append(4) 
>>> x 
deque([2, 3, 4], maxlen=3) 
>>> x.append(5) 
>>> x 
deque([3, 4, 5], maxlen=3) 

這可以讓你遍歷文件,但保存您在方便的方式閱讀的最後3行,任何時候第一要素符合您的條件,只要輸出匹配的行和以下兩條,只要它們不符合您的條件即可。

+0

這很聰明,但不是它會將某些行寫入兩次嗎?還有,應該在循環結束時進行檢查,以確保倒數第二行不應觸發寫入。 – mgilson

+0

剛剛編輯解決這些問題,我不知道是否需要重複行,但他們可能不應該在那裏。 –

+0

請忽略我的(現已刪除)評論。這是不正確的。 – mgilson

2

我在翻譯這僞碼企圖說:

For each (Line) { 
     If Next Line is "Trig1" AND Current Line is "silence.wav" 
      Log it 
} 
## And We're Done 

(歡迎隨時指正)

你缺少Trig6因爲你問的是沒有按「下一行不存在。你可以改寫它,而不是轉發,而是解決你的問題嗎?

1

你真的應該學會使用正則表達式(模塊re)
當你想分析文本時,這是必須的。

看看它允許做的事情:

import re 

ss = """trig1.RESP: 
stim4: silence.wav 
trig1.RESP: 
trig6.RESP: 1 
trig1.RESP: 
trig1.RESP: 
trig5.RESP: 1 
stim5: silence.wav 
trig1.RESP: 
trig6.RESP: 1 
stim3: silence.wav 
trig1.RESP: 
stim5: silence.wav 
trig1.RESP: 
trig6.RESP: 1 

stim777: silence.wav 
stim111: silence.wav 
trig1.RESP: 
trig6.RESP: 1 
trig1.RESP: 
trig6.RESP: 1""" 

pat = ('^(.+silence.wav.*)(?<!) *\n' 
     '(?:(?!.*silence.wav)(.*)(?<!) *\n)?' 
     '(?:(?!.*silence.wav)(.*)(?<!) *)?') 

RE = re.compile(pat,re.MULTILINE) 

for tugr in RE.findall(ss): 
    print tugr 

結果

('stim4: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1') 
('stim5: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1') 
('stim3: silence.wav', 'trig1.RESP:', '') 
('stim5: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1') 
('stim777: silence.wav', '', '') 
('stim111: silence.wav', 'trig1.RESP:', 'trig6.RESP: 1') 

,然後你做你想要用線

拍拍的這些元組的是作爲一個字符串定義正則表達式的模式。
RE是一個正則表達式編譯,它是具有方法搜索匹配的findall

括號()定義一組中的對象。
一個組捕獲文本的某些部分。 但(?: )定義了一個組,它不捕獲它匹配的文本部分。對部分文本採取行動很有用,例如將限定符*?+置於組尾部。

當第三行有'silence.wav'時,它必須保持不匹配, ,當第二行有'silence.wav'時,只有第一行必須匹配。 這就是爲什麼在模式的兩個地方有(?.*silence.wav)的部分。

^是符號意思
^「串開始」旗re.MULTILINE裝置

「的線的開始」的部分的圖案的(?<!) *在那裏沒有趕上空格處的端部線。

一個圖案,點.意味着「任何字符」,除了LF字符

\n 

等穴,上,如果你需要我可以回答你。

+0

感謝您的建議。我認爲你也是對的。下一步,學習正則表達式。得到它了。 :) – user1867442