4

非常に大きなファイルがfoo.txtあり、正規表現を見つけたらそれを繰り返して何かを実行したいとします。現在私はこれを行います:

f = open('foo.txt')
s = f.read()
f.close()
for m in re.finditer(regex, s):
    doSomething()

ファイル全体をメモリに保存せずにこれを行う方法はありますか?

注:正規表現は複数行にまたがる可能性があるため、ファイルを1行ずつ読み取ることはできません。

stdin更新:可能であれば、これも使用したいと思います。

更新:カスタムファイルラッパーを使用して文字列オブジェクトをエミュレートすることを検討していますが、正規表現関数がカスタム文字列のようなオブジェクトを受け入れるかどうかはわかりません。

4

4 に答える 4

5

式の可能な最大長を可能にするためにオーバーラップしてファイルをチャンクごとに読み取る必要があるか、ストリームを使用するのとほぼ/同じように機能するマップトファイルを使用する必要があります:https://docs。 python.org/library/mmap.html

UPDATEのUPDATE:stdinはファイルではなく、ファイル記述子などがあるという点で、stdinと非常によく似た動作をすることを考慮してください。これはposixストリームです。違いがよくわからない場合は、グーグルで調べてみてください。OSはそれをmmapできないため、pythonはできません。

また、あなたがしていることは、正規表現を使用するのに不適切なことかもしれないと考えてください。正規表現は、接続文字列、ログエントリ、csvデータなどの解析などの小さなものをキャプチャするのに最適です。これらは、大量のデータを解析するための優れたツールではありません。これは仕様によるものです。カスタムパーサーを作成する方がよい場合があります。

過去からのいくつかの知恵の言葉:http: //regex.info/blog/2006-09-15/247

于 2012-06-20T20:40:30.647 に答える
5

正規表現がまたがることができる行数を適切な数に制限できる場合は、を使用collections.dequeしてファイルにローリングウィンドウを作成し、その行数のみをメモリに保持できます。

from collections import deque

def textwindow(filename, numlines):
    with open(filename) as f:
        window   = deque((f.readline() for i in xrange(numlines)), maxlen=numlines)
        nextline = True
        while nextline:
            text = "".join(window)
            yield text
            nextline = f.readline()
            window.append(nextline)

 for text in textwindow("bigfile.txt", 10):
     # test to see whether your regex matches and do something
于 2012-06-20T20:51:54.017 に答える
0

おそらく、ファイルの一度に1行を生成する(1行を読み取る)関数を記述し、EOF信号を生成するまでその上でre.finditerを呼び出すことができます。

于 2012-06-20T20:37:51.043 に答える
0

これは別の解決策です。内部テキストバッファを使用して、ファイル全体をメモリにロードせずに、見つかった一致を徐々に生成します。

このバッファは、ファイルテキストを「スライドするウィンドウ」のように機能し、見つかった一致を生成しながら前進します。

ファイルの内容はチャンクによってロードされるため、これは、このソリューションが複数行の正規表現でも機能することを意味します。

def find_chunked(fileobj, regex, *, chunk_size=4096):
    buffer = ""

    while 1:
        text = fileobj.read(chunk_size)
        buffer += text
        matches = list(regex.finditer(buffer))

        # End of file, search through remaining final buffer and exit
        if not text:
            yield from matches
            break

        # Yield found matches except the last one which is maybe 
        # incomplete because of the chunk cut (think about '.*')
        if len(matches) > 1:
            end = matches[-2].end()
            buffer = buffer[end:]
            yield from matches[:-1]

ただし、一致するものがまったく見つからない場合は、ファイル全体がメモリに読み込まれる可能性があるため、ファイルに正規表現パターンが何度も含まれていると確信できる場合は、この関数を使用することをお勧めします。

于 2018-05-07T22:42:57.370 に答える