如何修改正则表达式仅匹配HTML标签内的on/data-callback属性
问题
我有一段PHP正则表达式,原本用于匹配<script>xxxx</script>内容,以及标签内的on...='xxx'、data-callback='xxx'属性:
$regex = '/(<script\b[^><]*>)(.*?)(<\/script>)|\b(on\w+|data-callback)\s*=\s*\K(?|(\')([^\'\\]*(?:(?:\\.|\'(?=[^)(]*\)))[^\'\\]*)*)\'|(")([^"\\]*(?:(?:\\.|"(?=[^)(]*\)))[^"\\]*)*)")/ism';
但发现非<script>部分会匹配标签外的对应字符串(比如标签文本内容里的data-callback='nnn')。当前使用该正则的代码及输出如下,期望修改后仅匹配标签内的目标属性:
<?php $regex = '/(<script\b[^><]*>)(.*?)(<\/script>)|\b(on\w+|data-callback)\s*=\s*\K(?|(\')([^\'\\]*(?:(?:\\.|\'(?=[^)(]*\)))[^\'\\]*)*)\'|(")([^"\\]*(?:(?:\\.|"(?=[^)(]*\)))[^"\\]*)*)")/ism'; $html="<script>yyyy</script>\n"; $html.="<a href='nnnn' onClick='yyy' ONF='yyy' data-callback='yyy'>data-callback='nnn'</a>\n"; $html.='<a href="nnn" data-callback="yyy" onClick="yyy">onkeypress=nnn onx="nnn" data-callback="nnn"</a>'; $result = preg_replace_callback($regex, function ($matches) { if (isset($matches[1])) $m1 = $matches[1]; else $m1 = ""; if (isset($matches[2])) $m2 = $matches[2]; else $m2 = ""; if (isset($matches[3])) $m3 = $matches[3]; else $m3 = ""; if (isset($matches[4])) $m4 = $matches[4]; else $m4 = ""; if (isset($matches[5])) $m5 = $matches[5]; else $m5 = ""; echo "\n<LI>cp : 1[$m1] 2[$m2] 3[$m3] 4[$m4] 5[$m5]"; $m0=substr($m5, 0, 1); if ( strcmp($m0, "'")==0 or strcmp($m0, '"')==0 ) $quote=$m0; else $quote=""; return $m1.$m0."ZZZZ".$m0.$m3; return "$m1$m2=".$quote."ZZZZZ".$quote.""; } , $html); echo "\n\n".$result;
当前输出:
<LI>cp : 1[<script>] 2[yyyy] 3[</script>] 4[] 5[] <LI>cp : 1[] 2[] 3[] 4[onClick] 5['] <LI>cp : 1[] 2[] 3[] 4[ONF] 5['] <LI>cp : 1[] 2[] 3[] 4[data-callback] 5['] <LI>cp : 1[] 2[] 3[] 4[data-callback] 5['] <LI>cp : 1[] 2[] 3[] 4[data-callback] 5["] <LI>cp : 1[] 2[] 3[] 4[onClick] 5["] <LI>cp : 1[] 2[] 3[] 4[onx] 5["] <LI>cp : 1[] 2[] 3[] 4[data-callback] 5["] <script>ZZZZ</script> <a href='nnnn' onClick='ZZZZ' ONF='ZZZZ' data-callback='ZZZZ'>data-callback='ZZZZ'</a> <a href="nnn" data-callback="ZZZZ" onClick="ZZZZ">onkeypress=nnn onx="ZZZZ" data-callback="ZZZZ"</a>
期望输出:
<script>ZZZZ</script> <a href='nnnn' onClick='ZZZZ' ONF='ZZZZ' data-callback='ZZZZ'>data-callback='nnn'</a> <a href="nnn" data-callback="ZZZZ" onClick="ZZZZ">onkeypress=nnn onx="nnn" data-callback="nnn"</a>
解决方案
修改正则表达式中匹配on*/data-callback属性的部分,给属性名前加上正向回溯预查断言,确保它处于HTML标签的起始部分(即位于<和>之间):
修改后的正则:
$regex = '/(<script\b[^><]*>)(.*?)(<\/script>)|(?<=<[^>]*)\b(on\w+|data-callback)\s*=\s*\K(?|(\')([^\'\\]*(?:(?:\\.|\'(?=[^)(]*\)))[^\'\\]*)*)\'|(")([^"\\]*(?:(?:\\.|"(?=[^)(]*\)))[^"\\]*)*)")/ism';
改动说明
- 原正则中匹配属性名的部分是
\b(on\w+|data-callback),现在改为(?<=<[^>]*)\b(on\w+|data-callback) (?<=<[^>]*)是正向回溯预查,表示匹配位置的左侧必须存在<且后面跟着任意非>的字符,这就确保了属性名是在HTML标签内部(还没到标签结束的>)- 保持其他部分不变,既保留了对script标签内容的匹配,又能精准匹配标签内的目标属性,不会误匹配标签文本中的内容
验证结果
运行修改后的代码,输出会符合预期:标签内的on*、data-callback属性值被替换为ZZZZ,而标签文本中的对应字符串则保持不变。
内容的提问来源于Stack Exchange,提问作者abe1432181
相关产品推荐
相关产品推荐

