13

私は200個までの短いテキストファイル(50kb)を持っていますが、それらはすべて同じような形式です。これらの各ファイルで特定の文字列を含む行を見つけて、その行と次の3行(ファイルの残りの行は除く)を別のテキストファイルに書き込みたいと思います。私はこれを行うために自分自身にPythonを教えようとしており、これを試すための非常に単純で粗雑な小さなスクリプトを作成しました。私はバージョン2.6.5を使用しており、Macターミナルからスクリプトを実行しています。

#!/usr/bin/env python

f = open('Test.txt')

Lines=f.readlines()
searchquery = 'am\n'
i=0

while i < 500:
    if Lines[i] == searchquery:
        print Lines[i:i+3]
        i = i+1
    else:
        i = i+1
f.close()

これは多かれ少なかれ機能し、出力を画面に出力します。しかし、代わりに行を新しいファイルに出力したいので、次のように試しました。

f1 = open('Test.txt')
f2 = open('Output.txt', 'a')

Lines=f1.readlines()
searchquery = 'am\n'
i=0

while i < 500:
if Lines[i] == searchquery:
    f2.write(Lines[i])
    f2.write(Lines[i+1])
    f2.write(Lines[i+2])
    i = i+1
else:
    i = i+1
f1.close()
f2.close()

ただし、ファイルには何も書き込まれません。私も試しました

from __future__ import print_function
print(Lines[i], file='Output.txt')

それを機能させることもできません。誰かが私が間違っていることを説明したり、代わりに私が何をすべきかについていくつかの提案をすることができれば、私は本当に感謝しています。また、検索を改善するための提案があれば、それらもいただければ幸いです。私は検索したい文字列が行の唯一のテキストであるテストファイルを使用していますが、実際のファイルでは、必要な文字列はまだ行の先頭にありますが、その後に他のテキストが続きます。私が今設定している方法も実際には機能しないと思います。

ありがとう、そしてこれが超基本的な質問であるならば申し訳ありません!

4

5 に答える 5

27

@ajonが指摘しているように、インデントを除いて、コードに根本的な問題はないと思います。インデントを修正すると、うまくいきます。ただし、改善の機会がいくつかあります。

1) Pythonでは、物事を反復処理する標準的な方法は、forループを使用することです。ループを使用する場合、for繰り返し処理するためにループカウンター変数を定義し、それらを自分で追跡する必要はありません。代わりに、あなたはこのようなものを書きます

for line in lines:
    print line

文字列のリスト内のすべての項目を繰り返し処理して印刷します。

2)ほとんどの場合、これはforループがどのように見えるかです。ただし、実際にループ数を追跡したい場合があります。あなたのケースはそのような状況です。なぜなら、その1行だけでなく、次の3行も必要であり、したがって、インデックス付けにカウンターを使用する必要があるからです(lst[i])。そのために、があります。これenumerate()は、アイテムのリストそのインデックスを返し、ループすることができます。

for i, line in enumerate(lines):
    print i
    print line
    print lines[i+7]

例のようにループカウンターを手動で追跡する場合は、次の2つがあります

3)それはとブロックi = i+1から移動する必要があります。どちらの場合も実行しているので、の後に配置します。あなたの場合、ブロックはそれ以上何もしません、そして排除することができます:ifelseif/elseelse

while i < 500:
    if Lines[i] == searchquery:
        f2.write(Lines[i])
        f2.write(Lines[i+1])
        f2.write(Lines[i+2])
    i = i+1

4)IndexErrorこれで、 500行より短いファイルが発生します。500のループカウントをハードコーディングする代わりに、反復するシーケンスの実際の長さを使用する必要があります。len(lines)あなたにその長さを与えるでしょう。whileただし、ループを使用する代わりに、forループを使用range(len(lst))して、ゼロから。までの範囲のリストを反復処理しますlen(lst) - 1

for i in range(len(lst)):
    print lst[i]

5) ファイルを閉じる処理を行うコンテキストマネージャーopen()として使用できます。コンテキストマネージャーはかなり高度な概念ですが、既に提供されている場合は非常に簡単に使用できます。このようなことをすることによって

with open('test.txt') as f:
    f.write('foo')

ファイルが開かれ、そのブロックf内でアクセスできるようになります。withブロックを離れると、ファイルは自動的に閉じられるため、ファイルを閉じるのを忘れてしまうことはありません。

あなたの場合、2つのファイルを開いています。これは、2つのwithステートメントを使用してネストするだけで実行できます。

with open('one.txt') as f1:
    with open('two.txt') as f2:
        f1.write('foo')
        f2.write('bar')

または、Python 2.7 / Python 3.xでは、2つのコンテキストマネージャーを1つのwithステートメントにネストします。

    with open('one.txt') as f1, open('two.txt', 'a') as f2:
        f1.write('foo')
        f2.write('bar')

6)ファイルが作成されたオペレーティングシステムによって、行末が異なります。UNIXライクなプラットフォームで\nは、OS Xが使用される前のMac \r、およびWindowsが使用し\r\nます。そのLines[i] == searchqueryため、MacまたはWindowsの行末には一致しません。file.readline()3つすべてを処理できますが、行末にある行末が保持されるため、比較は失敗します。これは、を使用して解決されます。これによりstr.strip()、最初と最後のすべての空白の文字列が削除され、行が終了していない検索パターンが比較されます。

searchquery = 'am'
# ...
            if line.strip() == searchquery:
                # ...

(を使用してファイルを読み取ることfile.read()と、を使用str.splitlines()することも別の方法です。)

ただし、検索文字列は実際には行の先頭に表示されるとおっしゃっていたので、str.startswith()次を使用してそれを実行しましょう。

if line.startswith(searchquery):
    # ...

7) Pythonの公式スタイルガイドであるPEP8は、他のほとんどすべて(変数、関数、属性、メソッド、モジュール、パッケージ)CamelCaseのクラスに使用することを推奨しています。したがって、使用するlowercase_underscore代わりに。これは間違いなく他のポイントと比較してマイナーなポイントですが、それでも早い段階で正しく理解する価値があります。Lineslines


したがって、これらすべてを考慮して、次のようにコードを記述します。

searchquery = 'am'

with open('Test.txt') as f1:
    with open('Output.txt', 'a') as f2:
        lines = f1.readlines()
        for i, line in enumerate(lines):
            if line.startswith(searchquery):
                f2.write(line)
                f2.write(lines[i + 1])
                f2.write(lines[i + 2])

@TomKが指摘したように、このコードはすべて、検索文字列が一致する場合、それに続く行が少なくとも2行あることを前提としています。その仮定に頼ることができない場合try...exceptは、@poorsodが提案するようなブロックを使用してそのケースに対処するのが正しい方法です。

于 2012-10-06T00:40:43.140 に答える
3

あなたの問題は一番下のファイルのタブだと思います。

次のように、ifLines[i]からafterまでインデントする必要があります。i=i+1

while i < 500:
    if Lines[i] == searchquery:
        f2.write(Lines[i])
        f2.write(Lines[i+1])
        f2.write(Lines[i+2])
        i = i+1
    else:
        i = i+1
于 2012-10-06T00:24:49.857 に答える
1

ajonは正しい答えを持っていますが、ガイダンスを探している限り、ソリューションはPythonが提供できる高レベルの構造を利用していません。どうですか:

searchquery = 'am\n'

with open('Test.txt') as f1:
  with open(Output.txt, 'a') as f2:

    Lines = f1.readlines()

    try:
      i = Lines.index(searchquery)
      for iline in range(i, i+3):
        f2.write(Lines[iline])
    except:
      print "not in file"

2つの「with」ステートメントは、例外が発生した場合でも、最後にファイルを自動的に閉じます。

さらに優れた解決策は、ファイル全体を一度に読み取ることを避け(ファイルの大きさを誰が知っているか)、代わりに、ファイルオブジェクトの反復を使用して行ごとに処理することです。

  with open('Test.txt') as f1:
    with open(Output.txt, 'a') as f2:
      for line in f1:
        if line == searchquery:
          f2.write(line)
          f2.write(f1.next())
          f2.write(f1.next())

これらはすべて、ターゲットラインを超えて少なくとも2つの追加ラインがあることを前提としています。

于 2012-10-06T01:11:44.463 に答える
1

問題としてファイルシステム関連の問題を回避するために、「Output.txt」以外のものを使用しようとしましたか?

これを診断する際に、ファンキーな予期しない問題を回避するための絶対パスについてはどうでしょうか。

このアドバイスは、単に診断の観点からのものです。OSXdtraceとdtrussもチェックしてください。

参照:macosXでのstrace-feopen<コマンド>と同等

于 2012-10-06T01:17:55.000 に答える
0

大きなデータを処理する場合、行ごとの書き込みが遅くなる可能性があります。一度に多数の行を読み書きすることにより、読み取り/書き込み操作を高速化できます。

from itertools import slice

f1 = open('Test.txt')
f2 = open('Output.txt', 'a')

bunch = 500
lines = list(islice(f1, bunch)) 
f2.writelines(lines)

f1.close()
f2.close()

行が長すぎてシステムによっては、500行をリストに入れることができない場合があります。その場合は、bunchサイズを縮小し、すべてを書き込むために必要な数の読み取り/書き込みステップを実行する必要があります。

于 2017-10-04T16:03:46.407 に答える