正则匹配URL异常:为何'test...'这类字符串会被误匹配?
URL匹配正则的调试与问题解决
最终调试完成的正则
最终确定的URL匹配正则:
/\b((https?:\/\/)?(www)?\S*\.\S*\b)/gim
最初版本的正则问题
一开始写出的正则:
/\b((https?:\/\/)?(www\.)?.*?\.[a-z]{2,4}(\/[^\s]*)?\b)/g
存在误匹配问题,会把包含URL的整段内容(比如 as as das d youtube.com/as/ass asd asd)都匹配进去,而不是只提取URL部分。
尝试组合正则优化提取逻辑
为解决上述问题,尝试用两个正则组合处理:
const regex1 = /\b((^https?:\/\/)?(^www\.)?.*?\.[a-z]{2,4}(\/[^\s]*)?)\b/; const regex2 = /((?!\s).)*$/; let match1 = 'www.youtube.com/as/ass asd asd'.match(regex1); let match2 = (match1?.[0] ?? '').match(regex2);
这个方法能提取单条消息里的第一个URL,但仍有缺陷:输入包含非HTTP/HTTPS协议的内容(比如 aaaa adsa ftssp://youtube.com/a/b/c asdasd https://youtube.com/e/f/g)时,会错误匹配ftssp://youtube.com/a/b/c这类不符合协议要求的字符串。
参考后的正则及误匹配问题
结合相关技术答案后写出的正则:
const regex = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w.-]+)+[\w\-_~:/?#[\]@!$&'()*+,;=.]+$/
这个正则基本能满足需求,但会误匹配test...、test..........这类纯连续点的字符串:
'test...'.match(regex) // true 'test..........'.match(regex) // true
误匹配原因及修复方案
原因分析
问题出在正则的域名匹配部分:[\w.-]+(?:\.[\w.-]+)+
[\w.-]+可以匹配test这类合法字符,但其中包含了.,导致(?:\.[\w.-]+)+这个分组可以匹配「点 + 点」的组合。比如test...会被拆解为:test+.+.,满足[\w.-]+(匹配test)加上至少一次(?:\.[\w.-]+)(匹配.+ .),因此被判定为匹配成功。
修复后的正则
把域名部分的[\w.-]+改为[\w-]+,移除其中的.,确保每个点后面必须跟着字母或数字,不能只出现连续的点:
const regex = /^(?:http(s)?:\/\/)?[\w-]+(?:\.[\w-]+)+[\w\-_~:/?#[\]@!$&'()*+,;=.]+$/
内容的提问来源于stack exchange,提问作者Mike K
相关产品推荐
相关产品推荐

