我正在编写一个Chrome扩展程序,其中涉及执行以下作业的批次:通过转换<
来清理可能包含HTML标记的字符串,分别为>
和&
至<
,>
和&
。
(换句话说,和PHP的htmlspecialchars(str, ENT_NOQUOTES)
相同 - 我认为没有必要转换双引号字符。)
这是迄今为止我发现的最快的功能:
function safe_tags(str) {
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') ;
}
但是当我必须一次性运行几千个字符串时,仍然存在很大的滞后。
有人可以改进吗?它主要用于10到150个字符之间的字符串,如果这有所不同的话。
(我有一个想法是不打扰编码大于号 - 这会有什么真正的危险吗?)
答案 0 :(得分:86)
这是你可以做到这一点的一种方式:
var escape = document.createElement('textarea');
function escapeHTML(html) {
escape.textContent = html;
return escape.innerHTML;
}
function unescapeHTML(html) {
escape.innerHTML = html;
return escape.textContent;
}
答案 1 :(得分:71)
您可以尝试传递回调函数来执行替换:
var tagsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};
function replaceTag(tag) {
return tagsToReplace[tag] || tag;
}
function safe_tags_replace(str) {
return str.replace(/[&<>]/g, replaceTag);
}
这是一个性能测试:http://jsperf.com/encode-html-entities与重复调用replace
函数,并使用Dmitrij提出的DOM方法进行比较。
你的方式似乎更快......
为什么你需要它呢?
答案 2 :(得分:27)
Martijn的方法作为原型函数:
String.prototype.escape = function() {
var tagsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};
return this.replace(/[&<>]/g, function(tag) {
return tagsToReplace[tag] || tag;
});
};
var a = "<abc>";
var b = a.escape(); // "<abc>"
答案 3 :(得分:9)
最快的方法是:
function escapeHTML(html) {
return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
}
此方法比基于'替换'的方法快两倍,请参阅http://jsperf.com/htmlencoderegex/35。
答案 4 :(得分:8)
AngularJS源代码的版本也在angular-sanitize.js内。
var SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g,
// Match everything outside of normal chars and " (quote character)
NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g;
/**
* Escapes all potentially dangerous characters, so that the
* resulting string can be safely inserted into attribute or
* element text.
* @param value
* @returns {string} escaped text
*/
function encodeEntities(value) {
return value.
replace(/&/g, '&').
replace(SURROGATE_PAIR_REGEXP, function(value) {
var hi = value.charCodeAt(0);
var low = value.charCodeAt(1);
return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';';
}).
replace(NON_ALPHANUMERIC_REGEXP, function(value) {
return '&#' + value.charCodeAt(0) + ';';
}).
replace(/</g, '<').
replace(/>/g, '>');
}
答案 5 :(得分:7)
一体化脚本:
// HTML entities Encode/Decode
function htmlspecialchars(str) {
var map = {
"&": "&",
"<": "<",
">": ">",
"\"": """,
"'": "'" // ' -> ' for XML only
};
return str.replace(/[&<>"']/g, function(m) { return map[m]; });
}
function htmlspecialchars_decode(str) {
var map = {
"&": "&",
"<": "<",
">": ">",
""": "\"",
"'": "'"
};
return str.replace(/(&|<|>|"|')/g, function(m) { return map[m]; });
}
function htmlentities(str) {
var textarea = document.createElement("textarea");
textarea.innerHTML = str;
return textarea.innerHTML;
}
function htmlentities_decode(str) {
var textarea = document.createElement("textarea");
textarea.innerHTML = str;
return textarea.value;
}
答案 6 :(得分:2)
更快或更短的解决方案是:
escaped = new Option(html).innerHTML
这与JavaScript的一些怪异痕迹有关,其中Option元素保留了一个自动进行这种转义的构造函数。
答案 7 :(得分:1)
function encode(r) {
return r.replace(/[\x26\x0A\x3c\x3e\x22\x27]/g, function(r) {
return "&#" + r.charCodeAt(0) + ";";
});
}
test.value=encode('How to encode\nonly html tags &<>\'" nice & fast!');
/*
\x26 is &ersand (it has to be first),
\x0A is newline,
\x22 is ",
\x27 is ',
\x3c is <,
\x3e is >
*/
<textarea id=test rows=11 cols=55>www.WHAK.com</textarea>
答案 8 :(得分:0)
Martijn的方法作为单一功能处理&#34; 标记(在javascript中使用):
function escapeHTML(html) {
var fn=function(tag) {
var charsToReplace = {
'&': '&',
'<': '<',
'>': '>',
'"': '"'
};
return charsToReplace[tag] || tag;
}
return html.replace(/[&<>"]/g, fn);
}
答案 9 :(得分:0)
我不太确定速度,但是如果您追求简单性,我建议您使用lodash /下划线escape函数。
答案 10 :(得分:0)
我将XMLSerializer
添加到堆中。它提供了最快的结果,而无需使用任何对象缓存(不在序列化器上,也没有在Text节点上)。
function serializeTextNode(text) {
return new XMLSerializer().serializeToString(document.createTextNode(text));
}
额外的好处是它支持序列化的属性与文本节点不同:
function serializeAttributeValue(value) {
const attr = document.createAttribute('a');
attr.value = value;
return new XMLSerializer().serializeToString(attr);
}
通过查看text nodes和attribute values的规范,您可以查看其实际替换的内容。完整的文档具有更多的节点类型,但是概念是相同的。
关于性能,如果不缓存,它是最快的。如果确实允许缓存,则在带有子Text节点的HTMLElement上调用innerHTML
最快。正则表达式将是最慢的(如其他评论所证明)。当然,XMLSerializer在其他浏览器上可能会更快,但是在我的(有限的)测试中,innerHTML
是最快的。
最快的单行:
new XMLSerializer().serializeToString(document.createTextNode(text));
最快的缓存:
const cachedElementParent = document.createElement('div');
const cachedChildTextNode = document.createTextNode('');
cachedElementParent.appendChild(cachedChildTextNode);
function serializeTextNode(text) {
cachedChildTextNode.nodeValue = text;
return cachedElementParent.innerHTML;
}
答案 11 :(得分:-2)
节目有点晚,但使用encodeURIComponent()和decodeURIComponent()有什么问题?