2015-11-08 10 views
7

regexの入力長がパフォーマンスに影響を与えない理由とその可能性はありますか?regexが文字列の長さを気にしない理由

生成される文字列は次のとおりです。128個のランダムな文字。括弧の中に2つの数字があります。これは何度も繰り返されます。

128 radnom characters....(-2435346|45436) 128 radnom characters....(-32525562|-325346) 

正規表現はすべての数字を括弧内に入れます。ここにパターンがあります。

\(([-+]?\d+\|[-+]?\d+)\) 

だから、試合が

-2435346|45436 
-32525562|-325346 
etc... 

のようになる。ここベンチマークを行うコードです。私はマッチングの時間だけを評価したいので、入力が生成された後にストップウォッチを開始します。

Random rand = new Random(); 
Func<string> getRandString = // generates 128 random characters. 
    () => Enumerable.Range(0, 128).Select(x => (char) rand.Next()).Aggregate("", (a, b) => a + b); 
Func<int> getRandInteger =() => rand.Next(); // generates random number. 
string format = "{0}({1}|{2})"; 

// Generate the big string. 
StringBuilder bigstr = new StringBuilder(); 
for (int i = 0; i < 100; i++) // repeat 100 times. 
{ 
    bigstr.Append(string.Format(format, getRandString(), getRandInteger(), getRandInteger())); 
} 
string input = bigstr.ToString(); 

Stopwatch stopwatch = Stopwatch.StartNew(); 
var matches = Regex.Matches(input, @"\(([-+]?\d+\|[-+]?\d+)\)"); 
stopwatch.Stop(); 
Console.WriteLine("Time Elapsed :\t{0}\nInputLength :\t{1}\nMatches Count :\t{2}", stopwatch.Elapsed, input.Length, matches.Count); 

私はループに10回繰り返す場合、これは私のコンソールで出力されます。

Time Elapsed : 00:00:00.0004132 
InputLength : 1500 
Matches Count : 10 

ループ1000回繰り返す場合。

Time Elapsed : 00:00:00.0004373 // seriously? 
InputLength : 149937 
Matches Count : 1000 

ループ1000000を繰り返すとします。

Time Elapsed : 00:00:00.0004900 // wtf? 
InputLength : 149964452 
Matches Count : 1000000 

スクリーンショットあなたが

enter image description here

を信じていけない場合、これは遅延評価のいくつかの種類ですか?もしそうなら、どのように試合の数を表示することができますか?どのように私はデバッガでこれをやったと私は一致を見ることができます。

私の正規表現のパターンには特別なものがあります。文字列の長さがパフォーマンスにどのように影響しないか?理解できません。

+0

ここには何も特別なものはありません。あなたの正規表現エンジンは文字列をトラバースし、あなたの正規表現にマッチするすべての状態を保存します。そして、あなたは1000時間の大きな文字列のベンチマークです。もっと大きな文字列。あるいはあなたのベンチマリコンは公平でないかもしれません。 – Kasramvd

+1

.NET regexエンジンで使用される文字列検索アルゴリズムの詳細については、[this answer of mine](http://stackoverflow.com/a/32618592/3764814)を参照してください。 –

+1

適切なベンチマーク:https://andreyakinshin.gitbooks.io/performancebookdotnet/content/science/microbenchmarking.html –

答えて

9

これが発生する理由の1つは、matches.Countプロパティが評価されていることです。遅延してです。ストップウォッチを止めると、マッチャーはマッチングを行う準備ができていますが、何も見つけられません。あなたがmatches.Countに電話をしたときだけ、それは動作を開始しますが、それまでにタイミングを停止しています。

単純な解決策は、あなたが時間を費やすコード部分にmatches.Countコールを移動することです。

もう1つの理由は、正規表現を解析するのに必要な時間を考慮していることです。これは、比較的高価な操作ですので、あなたは、より良いタイミングのためにストップウォッチをオンにする前にそれを行う必要があります。しかし、

Regex testRegex = new Regex(@"\(([-+]?\d+\|[-+]?\d+)\)"); 
Stopwatch stopwatch = Stopwatch.StartNew(); 
var matches = testRegex.Matches(input); 
var matchesCount = matches.Count; 
stopwatch.Stop(); 
Console.WriteLine("Time Elapsed :\t{0}\nInputLength :\t{1}\nMatches Count :\t{2}", stopwatch.Elapsed, input.Length, matchesCount); 

今10試合対万本のマッチのための時間の成長はかなりの(00:00:00.012984400:00:00.0843982)となり入力の長さの差が1000倍になると予想されるほど大きくはありません。

+0

LOL、私は時間が実際に文字列を生成するためだと思った。どのような愚かな間違い!私もデバッガでこれをしましたが、私は 'Regex.Matches'の後にブレークポイントを入れました。とにかくありがとう! M.kazemAkhgary @ –

+1

は、ここで[ 'MatchCollection'の実装](http://reflector.webtropy.com/default.aspx/[email protected]/[email protected]/DEVDIV_TFS/Dev10/Releases/RTMRel/ndp/fx/ですsrc/Regex/System/Text/RegularExpressions/RegexMatchCollection @ cs/1305376/RegexMatchCollection @ cs)。コードから、すべての作業を行う 'GetMatch'メソッドが遅れて呼び出されることがわかります。あなたが提供リンク – dasblinkenlight

+0

@dasblinkenlight私のために動作しません(Webページが不正な形式であり、すべてのコードが背景と同じ色である)、[ここで、参照ソース内の同じメソッドへのリンクがある](のhttp:// referencesource Microsoft.com/System/regex/system/text/regularexpressions/RegexMatchCollection.cs.html#682620f47b442b05) –

関連する問題