2010-12-27 30 views
18

私は大文字と小文字のC#正規表現を解釈すると問題なく動作しますが、少し遅いです。私はRegexOptions.Compiledを設定することでこれをスピードアップしようとしています、そして、これは最初の時間は約30秒かかると思われます。私は最初にアセンブリに正規表現をコンパイルすることでこれを無効にしようとしているので、私のアプリはできるだけ早くすることができます。なぜ私の正規表現は翻訳よりもずっと遅くコンパイルされていますか?

Regex myComplexRegex = new Regex(regexText, RegexOptions.Compiled); 
MatchCollection matches = myComplexRegex.Matches(searchText); 
foreach (Match match in matches) // <--- when the one-time long delay kicks in 
{ 

} 

または事前にRegex.CompileToAssembly使用:

MatchCollection matches = new CompiledAssembly.ComplexRegex().Matches(searchText); 
foreach (Match match in matches) // <--- when the one-time long delay kicks in 
{ 

} 

これが作ってアセンブリにコンパイルされたコンパイルの遅延は、それがアプリでコンパイルされていますか、起こったとき

私の問題はあります私はまだ最初のforeach呼び出しで遅延を得るので、基本的に役に立たない。私が望むのは、(Regex.CompileToAssembly呼び出しで)コンパイル時に実行時にではなく、コンパイル時にすべてのコンパイル遅延を実行することです。どこが間違っていますか?

(アセンブリにコンパイルする際に使用するコードは、http://www.dijksterhuis.org/regular-expressions-advanced/と似ています)。

編集:new CompiledAssembly.ComplexRegex().Matches(searchText);でコンパイルアセンブリを呼び出すとき

私はnewを使用する必要がありますか。それはそれがなくても "オブジェクト参照が必要"というエラーを出します。

アップデート2の回答/コメント

感謝。私が使用している正規表現はかなり長いですが、基本的には単純です。数千語のリストが|で区切られています。私はそれが本当にバックトラッキングの問題になるのを見ることができません。件名の文字列は1文字の長さに過ぎず、それでもコンパイルの遅延が発生する可能性があります。 RegexOptions.Compiled regexでは、正規表現に5000語が含まれている場合、実行に10秒以上かかるでしょう。比較のために、正規表現のコンパイルされていないバージョンは30,000以上の単語をとり、まだ瞬時に実行することができます。私は私が見つけた何を考えてこの上の多くのテストを行った後

は、次のとおりです。

    あなたの正規表現は多くの選択肢を持っているとき
  • はRegexOptions.Compiledを使用しないでください - それはへのへの極端に遅くなることがありますコンパイル。可能であれば、lazy evaluation for regexを使用し、AFAIはこれが(少なくともある程度は)正規表現のコンパイルにも拡張されていることがわかります。正規表現は完全にコンパイルされていなければならず、コンパイルを強制する方法がないようです。
  • Regex.CompileToAssemblyは、正規表現が完全にコンパイルされなければならない場合には、はるかに役立ちます。

私が間違っているか何かを見つけられない場合は、私に修正してください!

+0

おそらく、実際の式とサンプル入力を共有しようとする必要があります。 – driis

+1

このポストをありがとう。いくつかのRegex by TwitterでJavaから.NETに移植された同じ問題がありました。 RegexOptions.Compiledと.CompileToAssemblyの両方が、アプリケーションが最初に一致しようとすると約10秒間ハングしました。 Regex.Compiledを削除しました。 – LongZheng

+2

MSDNは、[regexのコンパイル済みアセンブリ](http://msdn.microsoft.com/en-us/library/gg578045.aspx#sectionToggle4)に対処した.NET 4のベストプラクティス記事を追加しました。 –

答えて

2

Regex.CompileToAssemblyを試してから、Regexオブジェクトを構築できるようにアセンブリにリンクしてください。 RegexOptions.Compiledは実行時オプションですが、アプリケーションを実行するたびに正規表現は再コンパイルされます。

+0

これは私がすでにやっていることです。残念ですが、残念です。 CompileToAssemblyコマンドはほとんど瞬時に動作します(少し時間がかかるはずだと思っていました)、代わりに正規表現を実行するときにforeachで遅延が発生します。 – mikel

+3

これを表示するために質問を更新できますか? '新しいRegex'をやっているのであれば、コンパイルされていない新しいRegexインスタンスを作っています。正規表現アセンブリでクラスを使用する必要があります。 – Douglas

+0

ダグラスに感謝します。私はそれを更新しましたので、うまくいけば、少しはっきりしています。 – mikel

7

RegexOptions.Compiledを使用する場合は、Regexオブジェクトを再利用する必要があります。あなたがこれをしているようには見えません。

RegexOptions.Compiledはトレードオフです。コードがオンザフライでコンパイルされるので、Regexの最初の構築は遅くなりますが、それぞれの一致はより速くなるはずです。実行時に正規表現が変更された場合、RegexOptions.Compiledの使用によるメリットはありませんが、実際の式に依存する可能性があります。コメント

あたり

更新、あなたの実際のコードは、あなたが投稿したもののように見える場合は、正規表現の新しい、オンザフライでコンパイルしたインスタンスごとに作成しているとして、あなたは、CompileToAssemblyのいずれかの利点を取っていませんそのコードが実行される時間。 CompileToAssemblyを利用するには、最初にRegexをコンパイルする必要があります。生成されたアセンブリをプロジェクト内で参照します。生成された強く型付けされたRegex型をインスタンス化する必要があります。

リンク先の例では、FindTCPIPという名前の正規表現があり、FindCTPIPという名前の型にコンパイルされます。遅い正規表現を調査することは、それはあまりにも後戻りすることであるとき

TheRegularExpressions.FindTCPIP MatchTCP = new TheRegularExpressions.FindTCPIP(); 

+0

Regex.CompileToAssemblyに転送された初期構造に遅延を伴うことは可能ですか?私はCompileToAssemblyの全体的なアイデアは、コンパイル時に構築の遅さをランタイムから削除することであったので、トレードオフはありません。 – mikel

+0

あなたの質問に投稿されたコードは、使用している実際のコードですか?この場合、毎回新しいRegexインスタンスを作成しているため、CompileToAssemblyは効果がありません。 – driis

+0

ご迷惑をおかけして申し訳ありません。質問を編集しました。私は両方の新しいRegex()オブジェクトを作成しようとしたり、例のようにインスタンス化し、どちらも私のために働くことはありません。正規表現がどちらかの方法で実行されたときにはまだ大きな遅延があり、それが実行時からコンパイル時に移そうとしています。 – mikel

2

非常に考えられる原因:これは使用する必要がある場合、1のような、この特定のタイプの新しいインスタンスを作成する必要があります。これはバックトラック数が存在しないか最小限になるように正規表現を書き換えることで解決されます。

正規表現とサンプル入力が遅い場所に投稿できますか?

個人的に私は正規表現をコンパイルする必要はありませんでしたが、このパスをとった場合のパフォーマンスに関する実際の数字を見るのは面白いです。

+0

ありがとう、私は詳細を投稿して更新しました。 RegexOptions.Compiledフラグがなくても非常に速いので、バックトラック問題だとは思わない。 – mikel

+0

非常に簡単に非効率な正規表現を書くことができます(ほとんど簡単です)。正規表現が基本的に交互に繰り返される場合、最適化はほとんどありません(しかし、余裕があります)。 「Catastrophic Backtracking」を引き起こすには1文字しかかからないため、注意してください。 http://www.regular-expressions.info/catastrophic.html 私はまだあなたの正規表現と遅いケースに興味があります。 – buckley

+0

'(?>サブ表現)'言語要素を使ってバックトラックを無効にすることもできます。これに関する詳細は、[.NET Frameworkの正規表現のベストプラクティス](http://msdn.microsoft.com/en-us/library/gg578045%28v=vs.110%29.aspx#)を参照してください。バックトラック)。 – Ronald

1

初期化を強制するには、空の文字列に対してMatchを呼び出すことができます。さらに、ngenを使用して式のネイティブイメージを作成し、プロセスをさらに高速化することができます。しかし、おそらく最も重要なのは、本質的には、単一のテキストに対してマッチするように巨大な大きな式をコンパイルするよりも、30.000 string.IndexOfまたはstring.ContainsまたはRegex.Matchステートメントを特定のテキストに対してスローするのと同じくらい速いことです。ステートマシンはずっと簡単なので、コンパイルやコンパイルなどが少なくて済みます。

あなたが考えることができる別のことは、テキストをトークン化し、それをあなたが後にしている単語のリストと交差させることです。

関連する問題