2016-08-01 54 views
3
var url = 'https://mp.weixin.qq.com/s?__biz=MzAxNjczMTQxMA==&mid=504131096&idx=1&sn=c2fe41152807821b7916fa9539a0cf87&scene=1&srcid=0718JR98ETFngTl6mDsNRfhK&key=77421cf58af4a65374324bd2f16d7fdd913230b5ab4bd48a72759cc99919893795265ff20c0c8a79c676e636f789899c&ascene=0&uin=MjAzOTExMTUxMg%3D%3D&devicetype=iMac15%2C1+OSX+OSX+10.11.5+build(15F34)&version=11020201&pass_ticket=kA76WNrCKCEZ3JyEii3tYs88BCmLEM%2FI4LPD%2FtHBzoPjYzI9t7seUadtUUVQ9677'; 
var reg = /^(http(s)?:\/\/)?(([\w\.]+)\.(?:com|cn|love|net|com\.cn|org)(\/|#|!|%|\w|\d|&|\?|-|=|~|\.|\+)*)$/; 
url.match(reg); 

我想测试一个字符串是否有效URL,但匹配语句会导致进程崩溃! - 浏览器或iOS应用程序,以后不会回应,CPU一直是90%+,可能是无限循环? 我的reg有什么不对或者这是一个正则表达式的BUG?这是一个正则表达式BUG吗?

我测试了JavaScript(http://regexr.com/),节点和iOS,它们返回超时或无响应(崩溃)。

+2

有一点是肯定的:问题是灾难性的回溯。 '(\/|#|!|%| \ w | \ d |&| \?| - | = |〜| \。| \ +)*'组正在杀死它,替换为一个字符类 - '[ !\ /#%\ W&\ - ?=〜+] *'。 –

+0

http://www.regular-expressions.info/catastrophic.html – daveoncode

回答

4

的问题是,最后的交替组具有字符串(即\w\d)的匹配在同一地点的几个分支,和*量词对组设置使得回溯工作努力尝试之前,所有可能的组合比赛失败。

你需要使用一个[\/#!%\w&?\-=~.+]字符类:

/^(http(s)?:\/\/)?(([\w.]+)\.(?:com|cn|love|net|com\.cn|org)[\/#!%\w&?\-=~.+]*)$/ 

regex demo

注意我不停的-逃脱字符类中,以免破坏如果模式是要在正则表达式将来会更新(-可以放在正则表达式模式的末尾或开始处以表示字面连字符,但有些开发人员倾向于将符号添加到字符类的末尾,有时会在不知道的情况下使用-创建一个范围那)。

+1

更确切地说:最简单的解决方法就是从最后一个组中删除'\ d',[它已经在工作](https: //regex101.com/r/lC1hA5/1),但字符类解决方案[效率更高](https://regex101.com/r/jT8pR3/1)(691步与4590步)。 –

+0

太棒了!你的回答非常清楚和正确。我不知道我不能同时放置(\ w | \ d),但它仍然适用于大多数测试字符串值(这就是为什么我没有及早发现此错误的原因)。是的,我想捕获(s)来决定它是http://还是https://或者是空的。非常感谢! –

+0

让我再说一遍:你可以使用'\ w | \ d',但是当你在一个更大的模式中使用它时,并且将一个量词设置到交替组时,灾难性的回溯将比以后更早发生。 **使用变更时,最好确保没有分支可以在同一地点匹配**。所以,不要使用'(灾难性的)',使用'灾难性的(?:al)?'。虽然如果按原样使用,这不是问题...我希望你明白:) –