web-dev-qa-db-ja.com

ストリームの正規表現を照合する適切なアルゴリズムは何ですか?

ストリームの正規表現パターンに一致させたいのですが、使用するアルゴリズムがわかりません。ファイル全体をメモリにロードしたくありません。

私はこれを行う方法を理解しようとしましたが、私は非常に基本的なアイデアしか持っていません。たとえば、一致が見つかれば、チャンクを何らかの集約文字列に連結できます。その後、試合の最後にアグリゲートをカットして続行します。しかし、一致しない場合、文字列全体をメモリにロードすることになります。

アグリゲートに最大サイズを指定することはできますが、そのようにして一致を失う可能性があります。同じ位置から始まるより長いマッチがある場合、私はそれを逃すことになる別の問題。したがって、このアルゴリズムは所有的数量詞とも互換性がないと思います。

この問題のより良い解決策はありますか?

1
inf3rno

これは難しい問題です。正規表現エンジンには、twpフレーバー(NFAおよびDFA)があります。

  1. DFA(確定的有限状態オートマトン)は効率的かつ限られたスペースで実行されますが、入力の部分文字列のキャプチャや逆参照など、おそらく望んでいるようなことはできません。 If必要なのは入力が一致するかどうかであり、whereではなく、それらが正しい方法ですトーゴ。

  2. NFA(非決定的有限オートマトン)は、基本的にbacktrackを実行できること、つまり、すでに消費されている入力を使用して何かを試すことに依存しています。また、問題は所有格指定子に限定されず、ほとんどの構成に限定されます。(A|B)でさえバックトラックが必要です。

一致の可能な長さを制限できる方法がある場合、正規表現エンジンの動作方法を変更するよりも、サイズ2 * Lの重複するチャンクに通常の一致を適用するのがほぼ確実に最善のオプションです。

ただし、変更する必要がある場合は、正規表現を分析するか、エンジンの進行状況を監視して、以前の入力がany一致の一部ではなくなる可能性があることを証明する必要があります。トップレベルのバックトラックが代替手段を使い果たしたとき。この時点で、文字を破棄して、操作全体に必要なメモリの量を制限できます。しかし、それは魅力的なプロジェクトになることに注意してください。つまり、ランダムな作業タスクを実行しようとしているだけであれば、予算の範囲外です。

2
Kilian Foth

一般に、このような巨大なファイル全体に正規表現を適用することはお勧めできません。実際のほとんどの場合、そのサイズのファイルは、ストリーミング形式で小さな文字列に分割するために使用できるある種の構造を持っています。これらの「ビルディングブロック」にのみ正規表現を適用すると、通常、パフォーマンスが向上し、メモリ効率の高いソリューションになります。

たとえば、コメントで、あなたは書きました

大規模なJSONがあり、そこからURLを抽出したいと考えています。

そのJSONファイルの正確な構造を知らなくても、URLは文字列リテラルでしか発生しないと思います。したがって、ここでできることは

  • Oboe.js のようなJSONストリーミングライブラリを利用する

  • jSONにURLが含まれている可能性がある各文字列リテラルに対して呼び出されるコールバックを実装します。そのコールバックでは、正規表現を使用して文字列内のURLを検出します。

ただし、これは単なる例であり、このアプローチを多くの比較可能なユースケースに適用できます。

6
Doc Brown