正则匹配html会误改属性值和url,因其无法区分文本内容与属性值;domdocument才是安全替代方案,通过解析成树结构仅操作文本节点。

正则匹配HTML会误改属性值和URL
最直接的问题是:正则无法区分文本内容和属性值。比如想把页面中所有 ts 替换为 s,但 <img src="cats.jpg"> 里的 ts 也会被干掉,变成 cas.jpg —— 资源路径就炸了。
常见错误现象:
-
preg_replace('/ts/', 's', $html)破坏所有含ts的 URL、class、data-属性 - 用
/>([^ 提取标签内文本,遇到 <code>@#@#@#@#@#@#@#@#@#@0就提前截断 - 自闭合标签(
<img>)、注释(<!-- -->)、CDATA 段全都不识别,直接漏匹配或错匹配
PCRE的(*SKIP)(*FAIL)只是缓解,不是根治
虽然 PHP 的 (*SKIP)(*FAIL) 技巧能跳过标签、只匹配外部文本,但它仍基于字符串扫描,不理解 HTML 结构语义。
使用场景受限于:
- 无法处理嵌套标签(如
<div><span>text</span></div>中的text可以匹配,但若中间穿插<script>alert("x<y")</script>,正则就乱套 - 对 SVG、MathML、模板语法(如
{{var}})完全无感知,可能把标签当普通文本替换 -
]*>这种轻量级标签匹配,在遇到<div onclick="if(a<b)"> 时会因 <code> 被当成标签起始而崩溃<h3>DOMDocument才是真正安全的替代方案</h3> <p>真正可靠的路径是放弃“在字符串里找标签”,改为“解析成树,只动文本节点”。PHP 的 <code>DOMDocument做这件事是设计初衷,不是权宜之计。实操建议:
- 用
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD)加载,避免自动补全 - 遍历所有
TEXT_NODE类型节点,对$node->nodeValue做正则替换,不影响属性、注释、脚本 - 需要保留原始编码?加上
LIBXML_ENCODING和mb_convert_encoding()配合处理 - 如果 HTML 来自不可信来源,先用
DOMPurify或htmlpurifier清洗,再进 DOM 流程
pattern 属性不是正则万能入口
有人以为 HTML 的
pattern属性证明“浏览器支持正则处理 HTML”,其实它只作用于单个<input>的值校验,和解析/替换整个 HTML 文档毫无关系。关键限制:
-
pattern隐式加了^和$,只能做全串匹配,不能用于提取或局部替换 - 不支持
g、m、y标志,也无法获取捕获组 - 对
type="number"、"range"等控件完全无效 - 移动端软键盘行为不受其控制,
pattern="[0-9]+"仍可能输入字母
真正难的不是写对一个正则,而是保证它在任意 HTML 结构、任意编码、任意用户输入下都不破坏语义。DOM 解析器天生具备这个能力;正则没有,也不该有。
- 用











