在前端开发中,处理用户输入的富文本内容时,我们通常需要对大部分HTML标签进行转义,防止恶意脚本注入,但又要保留部分合法的展示类标签。使用JavaScript的正则表达式负向先行断言,可以高效实现这个需求,不需要逐个判断标签类型。

负向先行断言基础语法
负向先行断言是正则表达式中的零宽断言,作用是判断某个位置之后的内容不满足指定的规则,语法为x(?!y),表示匹配x,仅当x后面不跟着y。在HTML标签转义场景中,我们可以用它来排除需要保留的标签。
基础示例
比如我们要匹配所有不是img的标签,就可以用负向先行断言来编写正则:
// 匹配不是img开头的标签 const reg = /<((?!img)[a-zA-Z]+)(.*?)>/g; const testStr = '<img src="test.jpg"><div>内容</div>'; console.log(testStr.match(reg)); // 输出 ["<div>"]
实现选择性转义函数
我们需要转义的是<和>,将它们分别转为<和>,同时保留指定的标签不被转义。首先定义需要保留的标签列表,然后编写对应的正则。
步骤1:定义保留标签列表
假设我们需要保留的标签是img、span、strong,先把它们整理成数组:
// 需要保留的HTML标签列表 const reservedTags = ['img', 'span', 'strong'];
步骤2:构造正则规则
利用负向先行断言,构造匹配除了保留标签之外所有HTML标签的正则:
// 将保留标签数组拼接成正则的或条件
const reservedTagReg = reservedTags.join('|');
// 匹配所有HTML标签,排除保留的标签
// 正则说明:< 匹配左尖括号,后面跟着任意字符直到遇到>,但标签名不能是reservedTagReg中的内容
const escapeReg = new RegExp(`<((?!${reservedTagReg})[^>]+)>`, 'g');
步骤3:编写转义函数
遍历匹配到的需要转义的标签,将其替换为转义后的内容:
/**
* HTML标签选择性转义函数
* @param {string} str 待处理的字符串
* @param {Array} reservedTags 需要保留的标签列表
* @returns {string} 转义后的字符串
*/
function selectiveEscapeHTML(str, reservedTags = ['img', 'span', 'strong']) {
if (typeof str !== 'string') return str;
const reservedTagReg = reservedTags.join('|');
// 匹配需要转义的标签:左尖括号 + 非保留标签名 + 任意非右尖括号字符 + 右尖括号
const escapeReg = new RegExp(`<((?!${reservedTagReg})[^>]+)>`, 'g');
return str.replace(escapeReg, (match) => {
// 转义左尖括号和右尖括号
return match.replace(/</g, '<').replace(/>/g, '>');
});
}
函数测试验证
我们传入包含多种标签的测试字符串,验证函数是否生效:
const testHTML = '<div class="box"><img src="test.jpg"><span>文本</span><script>alert(1)</script></div>'; const result = selectiveEscapeHTML(testHTML); console.log(result); // 输出:<div class="box"><img src="test.jpg"><span>文本</span><script>alert(1)</script></div>
可以看到div、script标签都被转义,而img、span标签保留原样,符合预期效果。
注意事项
- 保留标签列表需要根据实际业务场景调整,不要保留script、iframe等危险标签
- 如果用户输入的内容中包含已经转义的标签,需要提前做反转义处理,避免二次转义
- 负向先行断言只判断位置,不会消耗字符,适合这种需要排除特定匹配的场景
JavaScript负向先行断言HTML标签转义正则匹配修改时间:2026-06-08 22:33:25