2012-11-30 12 views
5

Python素人がここにあります。私は何千もの行に関する情報をリストアップしたテキストファイルを持っており、パターンと一致するかどうかに基づいて行とそれに続く2行を選択しようとしています。 は、私はちょうど私に興味のあるファイルの一部を含むように、元のファイルから絞り込まてきたので、私の現在のファイルには、次のようになります。基本的には何をなどtxtドキュメントの複数の行を選択し、Pythonで新しいテキストdocに書き込む問題。

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部分とそれに続く2行を含むすべての行を書き出すことです。それはsilence.wavラインと応答(私が最も興味がある部分、応答前TRIG1を持っている行を出力するので

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() 

これは、ほとんどの部分は正常に動作します:私は、次のコードを使用しましたこの時点ではあまり重要ではない)。しかしラインが行くとき、私はに実行し、問題がある:

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

私の出力がSTIM3(現在の行)とstim5(TRIG1をスキップした後に次の行を)書きますので、私はそれが次に移り考えます"stim:silence.wav"と書かれたときに前のコマンドに含まれていたので、stim5をスキップします。 私はtrig6.RESPが必要です:stim5の後に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

一つの可能​​なアプローチでは、一度に3行を追跡することができるように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パラメータを提供する場合、あなたは1に追加要素を追加するとき終了要素は、例えば、もう一方の端のポップさ:

>>> 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行を保存することができますはあなたの条件にマッチし、あなたの条件にも合致しない限り、一致した行と次の2行だけを出力します。

+0

これは賢いですが、いくつかの行を2回書き込んでいませんか?また、ループの最後に2番目から最後の行が書き込みを引き起こしてはならないことを確認する必要があります。 – 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 

あなたは「doesnの次の行を求めているので、あなたが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など

括弧は()グループを定義を有するオブジェクトの、コンパイルされた正規表現です。
グループは、テキストの特定の部分をキャプチャします。 しかし、(?: )は、一致するテキスト部分をキャッチしないグループを定義します。たとえば、グループの最後に修飾子*または?または+を挿入するなど、テキストの一部を処理すると便利です。

3番目の行に 'silence.wav'がある場合、それは一致しないままでなければなりません。 2番目の行に 'silence.wav'がある場合、最初の行のみが一致する必要があります。 パターンの2か所に部分(?.*silence.wav)があるのはこのためです。

^フラグre.MULTILINE手段「線の開始」と「文字列の先頭」
^を意味する記号である

部分パターンの(?<!) *の末尾に空白がキャッチしないようにされていますライン。

パターンのポイント.はあなたが必要とする場合、私はあなたに答えることができた上でLF文字

\n 

そして、他の点を除いて、「任意の文字」を意味します。

+0

提案していただきありがとうございます。私はあなたも正しいと思います。次のステップでは、正規表現を学びます。とった。 :) – user1867442

関連する問題