以前の今日、私は仕事の同僚にそれを再伝えました。Pythonのfinditer()は、通常、文字の反復可能な文字から字句解析器を手で転がすのではなく、入力をトークン化するための推奨される方法です。 彼はそれがメモリ内のファイル全体を読む必要があると言いました。 その場で、私はあなたがおそらくそれを行ごとに読んで、reを呼び出すことができると恥ずかしそうに言いました。トークン正規表現が行の境界を越えない場合は、finditer()を繰り返します。
それは本当だが、大きな答えではない。 それは連鎖reを構築することが判明しました。文字列のiterableからのfinditer()は可能ですが、それほど簡単ではありません。
ここでの最初の試みは、主なアイデアを示しています:re以来。finditer()の一致は重複しておらず、すべての一致が使い果たされた後、次のre。finditer()は、一致しない文字列の残りの部分から再開する必要があります。
def finditer_chained_bad(pattern, strings, flags=0): last = '' for s in strings: m = None for m in re.finditer(pattern, last + s, flags): yield m if not m: last = '' ##1 continue # m is the last match object. last = s
コメント付きの行##1
が競合点である可能性があります。 再場合.finditer()は一致しませんでしたが、ここでの実装の決定は、一致するものがないと仮定してsを完全に破棄することですが、潜在的な一致が入力文字列の境界を越えている可能性があると主張することができます。 これがlast += s
に変更された場合、入力の長いスパンが一致しなかった場合、無限のメモリ成長を犠牲にして、潜在的な一致が入力境界を越えた場合に機能 それは潜在的な一致が入力チャンクサイズよりも大きいことを意味するので、完全な一致を得るためには、チャンクサイズを動的に増やす必要があ
別の問題は、最後の一致が次の文字列に続く部分一致である可能性があることです。 単純にそれを降伏させると、呼び出し元は壊れた部分一致を取得します。 これを説明するために、入力が8つの文字列にチャンクされていると仮定します。
def main(): for m in finditer_chained_bad(r'\w+', ): print m.group(0)
は次のように出力します。
helloworld
“world”という単語は、文字列の境界のために誤って2つの一致に分割されています。 これを修正するには、最後の試合を延期し、次の再試合を再開するだけです。最後の一致の先頭からfinditer()。 完全な作業コードは次のようになります:
def finditer_chained(pattern, strings, flags=0): last_s = '' for s in strings: last_m = None last_s += s for m in re.finditer(pattern, last_s, flags): if last_m: yield last_m last_m = m if not last_m: continue assert last_m is m last_s = s if last_m: yield last_m
そしてそれは正しく印刷します:
helloworld
結果のfinditer_chained()は、ファイルがreかのように行の反復可能であるため、ファイfinditer()はファイル全体に適用されます。 そして、それはメモリ内のファイル全体を読み込まずに動作します。