12

この正規表現を使用して、ファイル内のタグの内容を取得します。

var regex = new RegExp("<tag:main>((?:.|\\s)*)</tag:main>");

これにより、v8 エンジンが無期限にハングします。

今、私が使用すればnew RegExp("<tag:main>([\s\S]*)</tag:main>")、すべてが良いです。

最初の時間が長すぎる理由を知っている人はいますか?

4

3 に答える 3

19

これは、最後の終了</tag:main>タグの後に発生する長い一連のスペースを壊滅的にバックトラックします。件名の文字列が 100 個のスペースで終わる場合を考えてみましょう。.最初に、それらすべてを交互の左側にあると一致させます。終了タグがないため失敗し、\s代わりに最後の文字を一致させようとします。これも失敗するため、最後から 2 番目のスペースを として、最後のスペースを として一致させようと\s.ます。それは失敗します(まだ終了タグはありません)ので、最後のスペースを\s. それが失敗すると、最後から 3 番目のスペースを a として\s一致させ、最後の 2 つのスペースと一致させるために 4 つの方法すべてを試みます。それが失敗すると、最後から 4 番目のスペースを\s最後の 3 つのスペースの 8 つのすべての方法。次に 16、32 など。最後から 100 番目のスペースに到達する前に、宇宙は終了します。

壊滅的なバックトラッキングのために永遠にかかる正規表現の一致に対して、異なる VM は異なる反応を示します。単に「一致しない」と報告するものもあります。V8 では、他の無限または無限に近いループを記述するのと同じです。

non-greedy*を使用すると、必要なことは実行されますが (最後ではなく最初の で停止したい場合</tag:main>)、終了シーケンスが欠落しているスペースの長い文字列に対して壊滅的なバックトラックが行われます。

内側の括弧内の同じ文字が交互の両側に一致しないことを確認すると、問題が指数関数的な問題から文字列の長さの線形の問題に軽減されます。代替の代わりに文字クラスを使用するか\n、代替バーの右側に配置します。 \nと素である.ため、長い一連のスペースにヒットした場合、正規表現エンジンは終了する前に左-右-左などのすべての組み合わせを試行しません。

于 2010-03-09T11:23:33.087 に答える
3

壊滅的なバックトラッキングだと思います。

問題の一部は、ドットと \s が相互に排他的ではないことにあると思います。

表情を変えたら

<tag:main>((?:.|[\r\n])*)</tag:main>

Regex Buddy デバッガーで実行すると、テスト文字列が一致しない場合にはるかに迅速に失敗します。

于 2010-03-09T09:32:08.203 に答える