Самый быстрый способ избежать тегов HTML как HTML-объектов?
Я пишу расширение для Chrome, которое включает в себя выполнение следующих задач: очистка строк, которые могут содержать теги HTML, путем преобразования <
, >
а также &
в <
, >
а также &
соответственно.
(Другими словами, так же, как PHP htmlspecialchars(str, ENT_NOQUOTES)
- Я не думаю, что есть реальная необходимость конвертировать символы в двойных кавычках.)
Это самая быстрая функция, которую я нашел до сих пор:
function safe_tags(str) {
return str.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>') ;
}
Но по-прежнему существует большое отставание, когда мне приходится проходить несколько тысяч строк за один раз.
Кто-нибудь может улучшить это? В основном это строки длиной от 10 до 150 символов, если это имеет значение.
(У меня была одна идея - не кодировать знак "больше чем" - будет ли в этом какая-то реальная опасность?)
10 ответов
Вы можете попробовать передать функцию обратного вызова для выполнения замены:
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
функционировать многократно, используя метод DOM, предложенный Дмитрием.
Ваш путь, кажется, быстрее...
Но зачем тебе это?
Вот один из способов сделать это:
var escape = document.createElement('textarea');
function escapeHTML(html) {
escape.textContent = html;
return escape.innerHTML;
}
function unescapeHTML(html) {
escape.innerHTML = html;
return escape.textContent;
}
Метод Мартина как функция-прототип:
String.prototype.escape = function() {
var tagsToReplace = {
'&': '&',
'<': '<',
'>': '>'
};
return this.replace(/[&<>]/g, function(tag) {
return tagsToReplace[tag] || tag;
});
};
var a = "<abc>";
var b = a.escape(); // "<abc>"
Еще более быстрое / короткое решение:
escaped = new Option(html).innerHTML
Это связано с каким-то странным пережитком JavaScript, когда элемент Option сохраняет конструктор, который выполняет этот вид экранирования автоматически.
Самый быстрый метод:
function escapeHTML(html) {
return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
}
Этот метод примерно в два раза быстрее, чем методы, основанные на "замене", см. http://jsperf.com/htmlencoderegex/35.
Источник: /questions/44609490/ekranirovanie-strok-html-s-pomoschyu-jquery/44609621#44609621
Исходный код 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, '>');
}
Скрипт "все в одном":
// 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;
}
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>
Я добавлю 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);
}
Вы можете увидеть, что он фактически заменяет, проверив спецификацию как для текстовых узлов, так и для значений атрибутов. В полной документации больше типов узлов, но концепция та же.
Что касается производительности, то он самый быстрый без кеширования. Когда вы разрешите кеширование, вызовитеinnerHTML
на HTMLElement с дочерним узлом Text - самый быстрый. Regex будет самым медленным (как доказывают другие комментарии). Конечно, 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;
}
Метод Мартина как отдельная функция с обработкой знака (используется в javascript):
function escapeHTML(html) {
var fn=function(tag) {
var charsToReplace = {
'&': '&',
'<': '<',
'>': '>',
'"': '"'
};
return charsToReplace[tag] || tag;
}
return html.replace(/[&<>"]/g, fn);
}
Я не совсем уверен в скорости, но если вы ищете простоту, я бы предложил использовать функцию escape- подчеркивания.
Немного опоздал на шоу, но что не так с использованием encodeURIComponent() и decodeURIComponent ()?