7

私がStringIO(からcStringIO)いくつか持っているとします。「Z」など、文字/バイトが検出されるまでバッファを読み取りたいので、次のようにします。

stringio = StringIO('ABCZ123')
buf = read_until(stringio, 'Z')  # buf is now 'ABCZ'
# strinio.tell() is now 4, pointing after 'Z'

Pythonでこれを行う最速の方法は何ですか? ありがとうございました

4

3 に答える 3

7

興味深い関連性の高い質問であるため、この質問がスタック オーバーフローに関して 1 つの回答しか得られないことに非常に失望しました。とにかく、ovgolovinだけが解決策を提供し、おそらく遅いと思ったので、より速い解決策を考えました:

def foo(stringio):
    datalist = []
    while True:
        chunk = stringio.read(256)
        i = chunk.find('Z')
        if i == -1:
            datalist.append(chunk)
        else:
            datalist.append(chunk[:i+1])
            break
        if len(chunk) < 256:
            break
    return ''.join(datalist)

これは io をチャンクで読み取ります (最初のチャンクにない終了文字が見つかった可能性があります)。各文字に対して呼び出される Python 関数がないため非常に高速ですが、逆に C で記述された Python 関数を最大限に使用します。

これは、ovgolovin のソリューションよりも約 60 倍速く実行されます。走っtimeitて確認しました。

于 2011-11-27T07:29:40.647 に答える
2
i = iter(lambda: stringio.read(1),'Z')
buf = ''.join(i) + 'Z'

ここでiterは、このモードで使用されます: iter(callable, sentinel) -> iterator.

''.join(...)かなり効果的です。「Z」を追加する最後の操作''.join(i) + 'Z'はあまり良くありません。ただし'Z'、イテレータに追加することで対処できます。

from itertools import chain, repeat

stringio = StringIO.StringIO('ABCZ123')
i = iter(lambda: stringio.read(1),'Z')
i = chain(i,repeat('Z',1))
buf = ''.join(i)

それを行うもう 1 つの方法は、ジェネレーターを使用することです。

def take_until_included(stringio):
    while True:
        s = stringio.read(1)
        yield s
        if s=='Z':
            return

i = take_until_included(stringio)
buf = ''.join(i)

いくつかの効率テストを行いました。説明されている手法のパフォーマンスはほとんど同じです。

http://ideone.com/dQGe5

于 2011-11-26T16:45:04.853 に答える