匹配HTML属性的正则陷入无限循环,如何报错或规避?
问题背景
现有用于匹配HTML标签名及属性的正则表达式:
<(?<nodeName>[a-zA-Z][-a-zA-Z0-9_]*)(?<attributes>(?:\s*[a-zA-Z_:!0-9,][-a-zA-Z0-9_:%.\"'`;(]*(?:\s*=\s*(?:(?:\"[^\"]*\")|(?:'[^']*')|{{[^>}]*}}|[^>]+|\w*))?)*)\s*(\/?)>
当输入存在引号不匹配的标签时(如下例),该正则会陷入无限循环:
<span class='Utils.showtt("{{getI18n('zr.ratings.reviews.client.review.tag', getCrmModuleInfo('Accounts', 'true'))}}")'>
需求:如何避免无限循环,或在出现此类情况时抛出错误?
解决方法
1. 优化正则表达式,消除回溯爆炸
原正则的属性匹配部分存在大量嵌套可选分支,遇到引号不闭合的情况时会触发大量回溯,导致无限循环。可以通过以下方式优化:
- 使用**原子组
(?>...)**包裹易回溯的片段,禁止正则引擎回溯到原子组内部 - 对引号匹配逻辑做更严谨的限制,未闭合的引号仅匹配到标签结束符
>前的内容,避免无意义的遍历
优化后的正则示例:
<(?<nodeName>[a-zA-Z][-a-zA-Z0-9_]*)(?<attributes>(?>\s*[a-zA-Z_:!0-9,][-a-zA-Z0-9_:%.\"'`;(]*\s*(?:=\s*(?>(?:"[^"]*")|(?:'[^']*')|{{[^>}]*}}|[^>"']+|\w*))?)*)\s*(\/?)>
核心改动:将属性匹配的核心片段放入原子组,减少回溯可能性;同时限制未闭合引号的匹配范围,避免引擎反复尝试无效分支。
2. 在代码层面添加超时控制
如果使用的编程语言支持,可以给正则匹配操作设置超时时间,超过阈值则终止匹配并抛出错误:
- Python:可结合
signal模块实现超时,或使用regex库的timeout参数 - JavaScript:部分环境(如Node.js 10+)支持正则的
timeout选项 - Java:通过
Pattern.compile时设置Pattern.TIMEOUT参数
3. 提前做引号配对预检查
在执行正则匹配前,先对输入字符串做简单的引号计数检查:
- 统计字符串中单引号、双引号的数量,若某类引号总数为奇数,直接判定为格式错误,抛出提示并跳过正则匹配
- 这种方式能快速过滤大部分引号不匹配的情况,避免进入正则匹配流程
内容的提问来源于stack exchange,提问作者MOHAMED SIKKANDAR AFZAL M
相关产品推荐
相关产品推荐

