/<img\b\s*([A-Za-z_][A-Za-z0-9-_]*(=(-?[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?|'[^']*'|"[^"]*"))?\s*)*>/
写成这样在js里能够不匹配,但依然用时很久。在PHP里还是灾难性回溯。
把规则放简单一点,忽略height=500.25
这种不加引号的写法,和selected
这种没有值的写法,就不会灾难性回溯了:
/<img\s*([A-Za-z_][A-Za-z0-9-_]*=('[^']*'|"[^"]*")\s*)+>/
至于“如何排除带 <> 的属性干扰”,答案倒是很简单:
('[^']*'|"[^"]*")
看起来这种写法的开销很大,这个?
是性能杀手。
(=('[^']*'|"[^"]*"))?
这个表达式在灾难性回溯的边缘,内容稍微多一点就要匹配很久:
/<img\s*([A-Za-z_][A-Za-z0-9-_]*(=('[^']*'|"[^"]*"))?\s*)+>/
匹配尝试了11万步:
总算找到灾难性回溯的根源了。
其实结尾的\s*
才是性能杀手。\s*
表示:属性之间可以有空格,也可以没有空格。
而“属性之间没有空格”这种选择,才是导致一系列回溯的原因,因为正则表达式引擎在试图把单个属性拆分成各个不同的部分(比如selected
可以切分成s
和elected
,还可以切分成se
和lected
,等等)。
改成\s+
并且放在属性的前面,就不会有这种问题了。
/<img(\s+[A-Za-z_][A-Za-z0-9-_]*(=(-?[0-9]+(\.[0-9]+)?([Ee][+-]?[0-9]+)?|'[^']*'|"[^"]*"))?)*\s*>/
现在最难的不匹配只需300步:
1楼的否定集合表示法也可以这样改造:
/<img(\s+[^\s<='"\/>]+(=([^"'<\/>]+|"[^"]*"|'[^']*'))?)*\s*>/
匹配48步:
不匹配300步:
性能相当优秀。
看起来,正则表达式很难完美的完成匹配,至少手写的不太行。总会有各种各样未能匹配到的特例。
就连完美的匹配这个字符串都很难:
"abc\"def\\" + "\\ghi\njkl"
不过如果只是匹配非常标准的HTML写法,没有不打空格不打引号等特例,那('[^']*'|"[^"]*")
应该就足够了。
举一个错误匹配的绝佳例子:
<div data-test='<img src="xxx.jpg">'></div>
在不进行全面语法分析的情况下,没有任何办法避免错误匹配到这个<img src="xxx.jpg">
。
找到了 登录账号以后就能用了
小米MIX2s(白)
regex101.com好像还有人给做了个中文版的: 嗨正则https://hiregex.com(这个好像还不是反代 ?)
坏孩子,其实你很好,但是还不够好
@水木易安,
可以匹配以下内容:
不匹配以下内容:
匹配以下内容时遇到回溯灾难(匹配永不结束),需要优化:
关于回溯灾难:https://hu60.cn/q.php/bbs.topic.89212.html
使用 https://regex101.com/ 进行正则表达式调试。注意:只有PCRE可以使用调试器,如果选了JS,调试器选项会消失。