5

文字列からすべての有効なURLを抽出する.Net正規表現があります。URLに疑問符が含まれている場合、1つを除いて20のユニットテストすべてに合格します。これにより、正規表現エンジンがプロセスをハングさせ、大混乱を引き起こします。

私はこの表現にかなりの時間を費やしましたが、問題を解決する方法がわかりません。うまくいけば、そこにある正規表現のプロが手を貸すことができます!2つの部分からなる質問:

1)文字列 " http://www.example.com/?a=1 "を評価するときにハングしないように、この正規表現パターンをどのように改善できますか。

正規表現パターン:

(?<URL>(\s|^)((?<Scheme>[A-Za-z]{3,9})[:][/][/])?([A-Za-z0-9-]+[.])+([A-Za-z]+){2,4}(?(Scheme)|[/])(((?:[\+~%\/.\w-_]*[/]?)?\??#?(?:[\w]*))?)*(\s|$))

この素晴らしいオンライン.Net正規表現テストエンジンを使用することをお勧めします:http://regexhero.net/tester/

2)正規表現エンジンのハングアップを防止/回復するために、呼び出しコードで何ができますか?呼び出しコードは次のとおりです。

        Regex linkParser = new Regex(UrlMatchRegex, RegexOptions.Compiled | RegexOptions.IgnoreCase);

        // Find matches and add them to the result
        foreach (Match m in linkParser.Matches(message))
        {
            result.Add(m.Value.Trim());
        }

私はこの特定の正規表現パターンにかなりの時間を費やし、見つけた少なくとも7つの代替案を試しました(このページのほとんどを含む:http://mathiasbynens.be/demo/url-regex)。まったく異なるパターンを使用するのではなく、既存のパターンを改善したいのですが、選択肢はあります。

最終正規表現v1:

いくつかの改訂の後、以下の助けを借りて、私の最終的な正規表現の一致は次のようになります。

(?<URL>((?<=\s)|^)((?<Scheme>[A-Za-z]{3,9})[:][/][/])?([A-Za-z0-9-]+[.])+[A-Za-z]{2,4}(?(Scheme)|[/]?)(((?:[\+~%\/.\w-_]*[/]?)?\??#?&?(?:[\w=]*))?)*((?=\s)|$))

** Regex v2:ドメイン、ポート番号、ハッシュタグのセットリストを含むように更新されましたが、末尾のスラッシュは取り込まれません

(?<URL>((?<=\b)|^)((?<Scheme>[A-Za-z]{3,9})[:][/][/])?([A-Za-z0-9-]+[.])+((?<TLD>\b(aero|asia|biz|cat|com|coop|edu|gov|info|int|jobs|mil|mobi|museum|name|net|org|pro|tel|travel|ac|ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|ax|az|ba|bb|bd|be|bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cd|cf|cg|ch|ci|ck|cl|cm|cn|co|cr|cu|cv|cx|cy|cz|cz|de|dj|dk|dm|do|dz|ec|ee|eg|er|es|et|eu|fi|fj|fk|fm|fo|fr|ga|gb|gd|ge|gf|gg|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|hk|hm|hn|hr|ht|hu|id|ie|il|im|in|io|iq|ir|is|it|je|jm|jo|jp|ke|kg|kh|ki|km|kn|kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|me|mg|mh|mk|ml|mn|mn|mo|mp|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nu|nz|nom|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|ps|pt|pw|py|qa|re|ra|rs|ru|rw|sa|sb|sc|sd|se|sg|sh|si|sj|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|tl|tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|ws|ye|yt|yu|za|zm|zw|arpa)\b))+(\/?)+((((?:[:\+~%/.\w-_\/])?[\?]?[#]?[&]?(?:[\w=]*))?)+(?=\?|\b)))

テストケース:これは#のテストです

一致しないでください:

like when you a/b test something
this sentence ends with a/
just a #hashtag

一致する必要があります:

sos.me extra
sos.me. extra <-- not period
sos.me, extra <-- not comma
sos.me/ extra <-- should match traililng /
sos.me/#hashtag? extra <-- not questionmark
sos.me? extra <-- not questionmark
www.sos.me? extra <-- not questionmark
sos.me/abcde extra
sos.me/abcde#hashtag extra
sos.me/abcdf/0 extra
sos.me/abcdf/0#hashtag extra
sos.me/something.aspx extra
sos.me/something.aspx#hashtag extra
http://something.com: extra <-- not colon
sos.me/something.aspx?name=value extra
sos.me/something.aspx?name=value#hashtag extra
http://something.com extra
https://something.com extra
http://something.com:80 extra
http://something.com:80/ extra <-- should match trailing /
http://something.com:80/?a=v&1=2 extra
http://something.com:80/?a=v&1=2#hashtag extra
http://something.com:80/?a=v&1=2# extra <-- should match trailing #
4

1 に答える 1

5

質問1

これは壊滅的なバックトラッキングを引き起こしています:

([A-Za-z]+){2,4}

と:

[\+~%\/.\w-_]*[/]?

私はあなたが意味したと推測しています:

([A-Za-z]{2,4})

と:

[\+~%\/.\w-_]*

あなたの正規表現は現在、等号を含む URL と一致しません。これが、壊滅的なバックトラッキングが最初に発生する理由です。

\??#?(?:[\w]*)

「=」を含まないため、「?a = 1」には一致しません。\wこれはかなり簡単に修正できます。

\??#?(?:[\w=%]*)

(私もそこに「%」を投げました)

また、正規表現は URL の前後の空白と一致しています。\sこれは、空白自体ではなく、空白の前後の位置に一致するため、ルックアラウンドを好む場合があります。

(?<URL>((?<=\s)|^)((?<Scheme>[A-Za-z]{3,9})[:][/][/])?([A-Za-z0-9-]+[.])+[A-Za-z]{2,4}(?(Scheme)|[/])(((?:[\+~%\/.\w-_]*[/]?)?\??#?(?:[\w=]*))?)*((?=\s)|$))

質問2

壊滅的なバックトラッキングを行う正規表現を検出または回復するためにできることは何もありません。あなたが試すことができる最善の方法は、正規表現を独立したスレッドにスピンオフし、特定のタイムアウト後にスレッドを終了することです。正確にそれを行う方法はまったく別の問題ですが、オンラインで .NET のチュートリアルを見つけることは難しくありません。

見る:

于 2013-01-28T20:34:48.037 に答える