2016-08-01 52 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)?'。雖然如果按原樣使用,這不是問題...我希望你明白:) –