3

多数の文字列を正規表現で解析する必要があるシナリオでは、すべてのテストで同じ RegEx ニードルが使用されることを考慮すると、高速になります。

  1. 配列内の各文字列を個別にテストするには、または;
  2. すべてを単一の大きな文字列に連結して、一度だけテストするには?

文字列の配列を処理するために RegEx エンジンを複数回起動する必要がないので、番号 2 が最適だと思いました。しかし、PHP (PCRE) でいくつかのテストを行った後、それは正しくないように思われました。

基準


PHP 5.3 (ソースコード)で簡単なベンチマークを作成したところ、次の結果が得られました。

5 秒で122185 回のインタラクションが配列内の複数の小さな文字列をテスト

単一の大きな文字列テストを実行して、5 秒間で26853回の対話

したがって、最初の方法は最大 5 倍高速であると結論付けなければなりません。ただし、これを確認する信頼できる回答を求めたいと思います。私が知らないPHPの最適化のために、私は物事を誤って想定している可能性があります。

特にPCREではなく、正規表現でテストする前に大きな文字列をフラグメント化することは、常により最適化されたソリューションですか?

preg_grep()

この関数はここでは考慮されるべきではないと思います。これはベンチマーク テストであり、最適化の問題ではありません。関数が PHP 固有のメソッドであることは言うまでもありません。また、preg_match_all一致したすべての部分文字列を返しますが、一致しpreg_grepた配列要素を示すだけです。

4

2 に答える 2

3

あなたのベンチマークには欠陥があります。あなたのコードのこの部分を見てください:

while(time() - $TimeStart < 5)
    for($i = 0; $i < $Length; $i++, $Iterations++)
    {
        preg_match_all($RegEx, $Input[$i], $m);
    }
}

は内ではなく、 内でのみ増やす$Iterations必要があります。前の結果を割ると、次のようになります。whilefor

24437 iterations using array
26853 iterations using big string

time()時間の測定には使用しないでくださいmicrotime()。精度を上げるにはより適しています。

最後に、このベンチマークは完全ではありません。両方のテストで同じ結果を得るには、array_merge()反復ごとに配列メソッドを実行する必要があるためです。また、どこかで大きな文字列を配列に変換する必要があり、それにも時間がかかります。

于 2012-12-24T05:32:00.740 に答える
1

すべてのターゲット文字列を 1 つにマージしないでください。1 つには、短い文字列で問題なく動作する多くの正規表現が壊れます。^$、 、\Aなどのアンカーは\z、突然一致するものがないことに気付くでしょう。また、固有の非効率性にもかかわらず短い文字列で動作する .*?` のようなものに大きく依存する正規表現は、Frankenstring で使用すると壊滅的に遅く.* orなる傾向があります。

しかし、連結されたバージョンの方が高速であることが判明したとしても、それは問題になるでしょうか? 配列バージョンを試してみて、遅すぎることがわかりましたか? これはかなり抜本的な解決策です (解決策である場合)。私があなただったら、解決できる問題が発生するまで実装を保留します。

于 2012-12-24T10:49:23.913 に答える