エッセイが書かれたドキュメントがあるとします。このエッセイを解析して、特定の単語のみを選択します。涼しい。
正規表現を使用すると、一致を探すためにファイルを1行ずつ解析するよりも速く実行できますか?もしそうなら、それはどのように機能しますか?どのようにして各単語を見るよりも速く進むことができますか?
どのように機能しますか?
オートマトン理論 を見てください
つまり、各正規表現には同等の有限オートマトンがあり、有限オートマトンにコンパイルおよび最適化できます。関連するアルゴリズムは、多くのコンパイラーの本に記載されています。これらのアルゴリズムは、awkやgrepなどのUNIXプログラムで使用されます。
ただし、最近のほとんどのプログラミング言語(Perl、Python、Ruby、Java(およびJVMベースの言語)、C#)では、このアプローチを使用していません。正規表現をコンパイルする再帰的バックトラッキングアプローチを使用しています正規表現のさまざまなサブチャンクを表すツリーまたはコンストラクトのシーケンスに変換します。最新の「正規表現」構文は、正規言語のグループの外にある後方参照を提供します(これらは有限オートマトンでは表現されません)。再帰的バックトラックアプローチ。
通常、最適化により、より効率的な状態マシンが生成されます。例:aaaab | aaaac | aaaadを考えてみてください。通常のプログラマーは、単純ですが効率の悪い検索実装(3つの文字列を別々に比較する)を10分で完了できます。しかし、それが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を含む一連のオブジェクトを作成します。
高速なコンピュータを使用しているため、正規表現は高速に見えます。
1 MIPSが高速なコンピューターであった1980年代に戻って、正規表現は遅くて醜く、計算集約型であるため、心配、懸念、研究のかなり大きな領域でした。巧妙なアルゴリズムの開発が続き、それを助けました-しかし、最近のすべての実用的な目的のために、亀裂を乗り越える高速機械の奇跡を見ています。
なぜドキュメントを検索するよりも速いと思いますか?
あなたができるいくつかのトリックがあります。 Aで始まりBで終わる10文字の単語を検索している場合、Aが見つかり、9文字目がBではない場合は、一部をスキップできます。参照 Knuth–Morris–Prattアルゴリズム
正規表現を速くするものは何ですか?
実際、そうではありません。それほどではありません。それは私たちのほとんどが気付くほどには遅くないというだけのことです。昔の遅い時代に戻って、それははるかに顕著でした。
それらは すべての仕事に適したツールではない-ハンマー でもあります。
ほとんどのライブラリは、多くの開発者が何年もの時間をかけて最適化し、可能な限りすべてのパフォーマンスを引き出すために作成したコードであるため、RegExは比較的高速でコードを記述できます。単一の個人がそれを自分の検索コードに複製することは困難です。
あなたの基本的な前提は間違っています。
正規表現は、単純な検索よりも高速であるとは限りません。それはすべてコンテキストに依存します。それは、式の複雑さ、検索されるドキュメントの長さ、および要素全体に依存します。
何が起こるかというと、正規表現は単純なパーサーにコンパイルされます(時間がかかります)。したがって、ドキュメントが小さい場合、この余分な時間はどの利点よりも重要です。また、式が単純な場合、正規表現は何の利点もありません。
式が複雑でドキュメントが十分に大きい場合は、いくつかの利点があります。これが正規表現をより高速であると見なすのに十分重要であるかどうかは、検索にどの程度の労力を費やしたいかに大きく依存します(また、正規表現には、ライブラリが提供するいくつかの最適化があり、自分では考えられなかった可能性があります)。
私が言おうとしていることは、一般化された包括的な答えはないということです。特定の式(および既知のドキュメントサイズ)がある場合、式が単純な検索よりも速いかどうか(およびその理由)のはい/いいえの答えを導き出すことができます。
正規表現の本当の利点は、それらの記述方法を理解すると、複雑な検索を簡潔に表現できることです。これは一般化された形式であるため、一般的な場合に役立つ方法で検索を可能にするツールを構築できます。通常、少なくとも単純な検索と同じくらい高速です(最小サイズのドキュメントでは、これよりも小さいドキュメントでは、速度が遅くても十分高速であるため、問題にはなりません)。
一部の高水準言語(おそらくjavascript)では、低水準言語(おそらくC)で実装された正規表現ライブラリを使用する方が、高水準言語でパーサーロジックを作成するよりも高速であると考えられます。
もっともらしい-これが実際に事実であるかどうかはわかりません。