エッセイが書かれた文書があるとします。このエッセイを解析して、特定の単語のみを選択します。クール。
正規表現を使用すると、ファイルを行ごとに解析し、単語ごとに一致を検索するよりも高速ですか?もしそうなら、それはどのように機能しますか?各単語を見るよりも速く進むにはどうすればよいですか?
エッセイが書かれた文書があるとします。このエッセイを解析して、特定の単語のみを選択します。クール。
正規表現を使用すると、ファイルを行ごとに解析し、単語ごとに一致を検索するよりも高速ですか?もしそうなら、それはどのように機能しますか?各単語を見るよりも速く進むにはどうすればよいですか?
回答:
どのように機能しますか?
つまり、各正規表現には同等の有限オートマトンがあり、コンパイルして有限オートマトンに最適化できます。関連するアルゴリズムは、多くのコンパイラの本で見つけることができます。これらのアルゴリズムは、awkやgrepなどのUNIXプログラムで使用されます。
ただし、最新のプログラミング言語(Perl、Python、Ruby、Java(およびJVMベースの言語)、C#)は、このアプローチを使用しません。再帰的なバックトラッキングアプローチを使用します。これは、正規表現を、ツリーまたは正規表現のさまざまなサブチャンクを表す一連の構造にコンパイルします。最新の「正規表現」構文は、通常の言語のグループの外にある後方参照を提供し(有限オートマトンでは表現しません)、再帰的なバックトラッキングアプローチで簡単に実装できます。
通常、最適化により、より効率的な状態マシンが生成されます。例:aaaab | aaaac | aaaadを考えてみてください。通常のプログラマは、10分ですぐに(3つの文字列を個別に比較して)シンプルで効率の悪い検索実装を取得できます。しかし、それがaaaa [bcd]と同等であることに気づいた場合、最初の4つの「a」を検索し、5番目の文字を[b、c、d]に対してテストすることにより、より良い検索を行うことができます。最適化のプロセスは、何年も前のコンパイラーのホームワークの1つでした。そのため、最新の正規表現エンジンにも最適化されていると思います。
一方、ステートマシンは、「単純な実装」と比較してより多くのスペースを使用するため、文字列を受け入れる場合にいくつかの利点があります。SQL文字列の引用符をエスケープしないプログラムを考えます。つまり、1)単一引用符で開始および終了します。2)単一引用符は、2つの連続した単一引用符によってエスケープされます。したがって、入力['a' '']は出力[a ']を生成するはずです。状態マシンでは、連続する単一引用符は2つの状態で処理されます。これらの2つの状態は、次の図に示すように、各入力文字が1回だけ処理されるように、入力履歴を記憶する目的に役立ちます。
...
S1->'->S2
S1->*->S1, output *, * can be any other character
S2->'->S1, output '
S2->*->END, end the current string
だから、私の意見では、些細なケースでは正規表現は遅くなるかもしれませんが、人間が最適化を確実に行うことができないという事実を考えると、通常は手動で作成された検索アルゴリズムよりも高速です。
(文字列の検索のような些細な場合でも、スマートエンジンは状態マップの単一のパスを認識し、その部分を単純な文字列比較に減らして、状態の管理を回避できます。)
フレームワーク/ライブラリの特定のエンジンは、プログラマが通常必要としない他の多くのことを行うため、低速になる場合があります。例:.NETのRegexクラスは、Match、Groups、Capturesを含む多数のオブジェクトを作成します。
aaaab|aaaac|aaaad
対言及した例でaaaa[bcd]
。この2つは数学的に同等であり、同じDFAを生成することを明示的に述べる価値があります。したがって、プログラマーは、理にかなった方法で正規表現を表現する自由を与えます(これは一般的な慣習ではありませんが...) ..
高速なコンピューターを使用しているため、正規表現は高速に見えます。
1 MIPSが高速コンピューターであった1980年代に戻って、正規表現は遅くてbigく、計算集約的であるため、心配、懸念、研究のかなり大きな領域でした。巧妙なアルゴリズム開発が続いて助けられました-しかし、最近ではすべての実用的な目的のために、高速マシンがひび割れを紙で覆っているという奇跡を見ています。
なぜ彼らは文書を検索するよりも速いと思いますか?
あなたができるいくつかのトリックがあります。Aで始まりBで終わる10文字の単語を検索する場合、Aを見つけ、さらに9桁上の文字がBでない場合、一部をスキップできます。Knuth–Morris–Prattアルゴリズムを参照してください
あなたの基本的な前提は間違っています。
正規表現は、単純な検索より常に高速であるとは限りません。それはすべてコンテキストに依存します。それは、表現の複雑さ、検索されるドキュメントの長さ、および多くの要因に依存します。
起こるのは、正規表現が単純なパーサーにコンパイルされることです(これには時間がかかります)。したがって、ドキュメントが小さい場合、この余分な時間がメリットを上回ります。また、式が単純な場合、正規表現は利点をもたらしません。
式が複雑で、ドキュメントが十分に大きい場合、いくつかの利点が得られます。これが正規表現の高速化を検討するのに十分なほど重要であるかどうかは、検索にどれだけの労力をかけるかによって大きく異なります(また、正規表現には、自分では考えられなかった最適化がライブラリによって提供される場合があります)。
私が言いたいのは、一般化された包括的な回答はないということです。特定の式(および既知のドキュメントサイズ)があれば、その式が単純な検索よりも速いかどうか(およびその理由)についてはい/いいえの答えを導き出すことができます。
正規表現の本当の利点は、それらの書き方を理解すると、複雑な検索を簡潔に表現できることです。これは一般化された形式であるため、一般的な場合に便利な方法で検索できるツールを作成できます。通常、少なくとも単純な検索と同じくらい高速です(最小サイズのドキュメントでは、これよりも小さいドキュメントでは、それが遅くても十分に高速であるため、重要ではありません)。
一部の高レベル言語(おそらくJavaScript)では、低レベル言語(おそらくC)で実装された正規表現ライブラリを使用すると、高レベル言語でパーサーロジックを記述するよりも高速になる可能性があります。
もっともらしい-これが実際に当てはまるかどうかはわかりません。