6

この質問は、次の投稿のフォローアップです: Javascript regex: Find all URLs outside <a> tags - Nested Tags

コードが次のことを発見しました:

\b((https?|ftps?):\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

http次のように forとftppart を別々に実行するのに比べて、非常に非効率的です。

\b(https?:\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

\b(ftps?:\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

regex101.com の例を次に示します。

しかし、私の HTML ページの 1 つで、これらのコードを85628ステップと7258 + 795ステップと比較すると、非常に異常です。

私が見た限りでは、(x|y)パターンを使用すると実行時間が短縮されますが、ここではおそらく奇妙な理由でそうではありません。

どんな助けでも大歓迎です。

4

2 に答える 2

3

あなたは壊滅的な後戻りの被害者のようです。

この正規表現は、わずか 3492 ステップでこのトリックを実行します。

\b(?>(https?|ftps?):\/\/[^"<\s]+)(?![^<>]*>|[^"]*?<\/a)

私が行ったのは、最初のグループをアトミックグループにしたことだけで、一致するとエンジンはすべてのバックトラッキングオプションを破棄します。

あなたの場合は正しいです。「URL を見つける」と「否定先読みを使用してそれを保持するかどうかを決定する」という 2 つの部分として考えることができます。元の正規表現は、先読みが失敗すると、URL 一致式にバックトラックします。ブロックはいくつかの[^"<\s]+シンボルを生成し、次に先読みを再試行し、さらにいくつかのシンボルを生成し、再試行します...

このhttps?|ftps?部分の追加によって事態がさら​​に悪化した理由は、これによりバックトラッキング (オプションの s が失われる) の余分なソースが提供され、その後のすべてのバックトラッキングが最初からやり直されるようになるためです。

regex101.com の左側のツールバーに「正規表現デバッガー」オプションがあることをご存知ですか? それを使用すると、正規表現がどのように一致するかが説明されるため、(先ほど行ったように)クレイジーなバックトラッキングがどこにあるかを把握できます。

ボーナス編集: 3185 ステップしかかからない、さらに改善されたもの:

\b(?>ht|f)tps?:\/\/(?>[^"<\s]+)(?![^<>]+>|[^"]*?<\/a)
于 2016-03-12T10:19:09.907 に答える
0

ソリューションよりもドキュメント内のすべてのリンクを検索する場合は、これです。配列を返します

document.anchors

于 2016-03-12T09:23:41.970 に答える