我有一个 .Net Regex 表达式,它从字符串中提取所有看起来有效的 Urls。它通过了我的所有 20 个单元测试,除了一个:当 Url 包含问号时。这会导致正则表达式引擎挂起进程并造成严重破坏。
我在这个表达式上花了很多时间,但我不确定如何解决这个问题。希望那里的正则表达式专业人士可以伸出援助之手!两部分问题:
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 Regex 测试引擎:http ://regexhero.net/tester/
2) 我可以在调用代码中做什么来防止/从 Regex 引擎挂起中恢复?这是调用代码:
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 #