web-dev-qa-db-fra.com

La méthode la plus rapide pour échapper aux balises HTML en tant qu'entités HTML?

J'écris une extension Chrome qui implique la réalisation d'un lot du travail suivant: nettoyage des chaînes qui pourraient contenir des balises HTML, en convertissant respectivement <, > et & en &lt;, &gt; et &amp; .

(En d'autres termes, identique à htmlspecialchars(str, ENT_NOQUOTES) de PHP - je ne pense pas qu'il soit vraiment nécessaire de convertir des caractères entre guillemets.)

C'est la fonction la plus rapide que j'ai trouvée jusqu'à présent:

function safe_tags(str) {
    return str.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;') ;
}

Mais il y a encore un grand retard lorsque je dois exécuter quelques milliers de chaînes en une fois. 

Quelqu'un peut-il améliorer cela? C'est surtout pour les chaînes entre 10 et 150 caractères, si cela fait une différence. 

(Une des idées que j’avais était de ne pas me préoccuper d’encoder le signe plus grand que cela - y aurait-il un réel danger?)

87
callum

Vous pouvez essayer de passer une fonction de rappel pour effectuer le remplacement:

var tagsToReplace = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;'
};

function replaceTag(tag) {
    return tagsToReplace[tag] || tag;
}

function safe_tags_replace(str) {
    return str.replace(/[&<>]/g, replaceTag);
}

Voici un test de performance: http://jsperf.com/encode-html-entities à comparer avec l'appel répété de la fonction replace et en utilisant la méthode DOM proposée par Dmitrij.

Ton chemin semble être plus rapide ...

Pourquoi en avez-vous besoin, cependant?

70
Martijn

Voici une façon de procéder:

var escape = document.createElement('textarea');
function escapeHTML(html) {
    escape.textContent = html;
    return escape.innerHTML;
}

function unescapeHTML(html) {
    escape.innerHTML = html;
    return escape.textContent;
}

Voici une démo.

83
Web_Designer

La méthode de Martijn en tant que fonction prototype:

String.prototype.escape = function() {
    var tagsToReplace = {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;'
    };
    return this.replace(/[&<>]/g, function(tag) {
        return tagsToReplace[tag] || tag;
    });
};

var a = "<abc>";
var b = a.escape(); // "&lt;abc&gt;"
26
Aram Kocharyan

La méthode la plus rapide est:

function escapeHTML(html) {
    return document.createElement('div').appendChild(document.createTextNode(html)).parentNode.innerHTML;
}

Cette méthode est environ deux fois plus rapide que les méthodes basées sur 'remplacer', voir http://jsperf.com/htmlencoderegex/35 .

Source: https://stackoverflow.com/a/17546215/698168

8
Julien Kronegg

Le code source d'AngularJS a également une version à l'intérieur de 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, '&amp;').
    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, '&lt;').
    replace(/>/g, '&gt;');
}
7
Kevin Hakanson

Script tout-en-un:

// HTML entities Encode/Decode

function htmlspecialchars(str) {
    var map = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        "\"": "&quot;",
        "'": "&#39;" // ' -> &apos; for XML only
    };
    return str.replace(/[&<>"']/g, function(m) { return map[m]; });
}
function htmlspecialchars_decode(str) {
    var map = {
        "&amp;": "&",
        "&lt;": "<",
        "&gt;": ">",
        "&quot;": "\"",
        "&#39;": "'"
    };
    return str.replace(/(&amp;|&lt;|&gt;|&quot;|&#39;)/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;
}

http://Pastebin.com/JGCVs0Ts

6
baptx

Une solution encore plus rapide/plus courte consiste à:

escaped = new Option(html).innerHTML

Ceci est lié à un étrange vestige de JavaScript dans lequel l'élément Option conserve un constructeur qui échappe automatiquement à ce type de sortie.

Crédit à https://github.com/jasonmoo/t.js/blob/master/t.js

2
Todd

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 &ampersand (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>

1
Dave Brown

Je ne suis pas tout à fait sûr de la vitesse, mais si vous recherchez la simplicité, je vous suggérerais d'utiliser la fonction lodash/underscore escape .

0
gilmatic

La méthode de Martijn en une seule fonction avec traitement "mark (using en javascript):

function escapeHTML(html) {
    var fn=function(tag) {
        var charsToReplace = {
            '&': '&amp;',
            '<': '&lt;',
            '>': '&gt;',
            '"': '&#34;'
        };
        return charsToReplace[tag] || tag;
    }
    return html.replace(/[&<>"]/g, fn);
}
0
iman