Encode HTML entities (v15)

Revision 15 of this benchmark created by Robert Simpson on


Description

Using replace with a single regular expression seems to be fastest method in various browsers based on http://jsperf.com/encode-html-entities/13. Now testing different methods of replacing the character with an HTML entity. Using an associative array is somewhat slower in IE than either of the two new methods are. Using an indexed array is slower in Firefox but faster in Opera and has the least amount of code. Using a switch statement is within a few percentage points of the fastest method in all browsers tested.

Preparation HTML

<script>
  function safe_tags_regex(str) {
    return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
  }

  function safe_tags_dom(str) {
    var div = document.createElement('div');
    div.appendChild(document.createTextNode(str));
    return div.innerHTML;
  }

  function safe_tags_dom2(str) {
    var div = document.createElement('div');
    div.innerText = str;
    return div.innerHTML;
  }

  var tagsToReplace = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };

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

  function safe_tags_replace_assoc(str) {
    return str.replace(/[&<>\"\']/g, replaceTagAssocArray);
  }

  var entitiesArray = ["&amp;gt;", "&amp;amp;", "&amp;apos;", "&amp;quot;", "&amp;lt;"];

  function replaceCharIndexedArray(char) {
    return entitiesArray[char.charCodeAt(0) % 25 % 6];
  }

  function safe_tags_replace_indexed(str) {
    return str.replace(/[&<>\"\']/g, replaceCharIndexedArray);
  }

  function replaceCharSwitch(char) {
    switch (char.charCodeAt(0)) {
    case 34:
      return "&quot;";
    case 38:
      return "&amp;";
    case 39:
      return "&apos;";
    case 60:
      return "&lt;";
    case 62:
      return "&gt;";
    }
    return char;
  }

  function safe_tags_replace_switch(str) {
    return str.replace(/[&<>\"\']/g, replaceCharSwitch);
  }

  function safe_tags_split_join(str) {
    for (var tag in tagsToReplace) {
      //if(Object.prototype.hasOwnProperty.call(tagsToReplace,tag)) {
      str = str.split(tag).join(tagsToReplace[tag]);
      //}
    }
    return str;
  }
</script>

Test runner

Ready to run.

Testing in
TestOps/sec
Using Regular Expression
var test = safe_tags_regex('if (a < b && c > d) {} // Héllö naõ');
ready
Using DOM textNode
var test = safe_tags_dom('if (a < b && c > d) {} // Héllö naõ');
ready
Using replace with associative array
var test = safe_tags_replace_assoc('if (a < b && c > d) {} // Héllö naõ');
ready
Using DOM innerText
var test = safe_tags_dom2('if (a < b && c > d) {} // Héllö naõ');
ready
Using split and join
var test = safe_tags_split_join('if (a < b && c > d) {} // Héllö naõ');
ready
customized
Encoder = {
  EncodeType: "entity",
  isEmpty: function(a) {
    if (a) {
      return ((a === null) || a.length == 0 || /^\s+$/.test(a))
    } else {
      return true
    }
  },
  HTML2Numerical: function(c) {
    var b = new Array("&nbsp;", "&iexcl;", "&cent;", "&pound;", "&curren;", "&yen;", "&brvbar;", "&sect;", "&uml;", "&copy;", "&ordf;", "&laquo;", "&not;", "&shy;", "&reg;", "&macr;", "&deg;", "&plusmn;", "&sup2;", "&sup3;", "&acute;", "&micro;", "&para;", "&middot;", "&cedil;", "&sup1;", "&ordm;", "&raquo;", "&frac14;", "&frac12;", "&frac34;", "&iquest;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&Auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&Ouml;", "&times;", "&oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&Uuml;", "&yacute;", "&thorn;", "&szlig;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&ouml;", "&divide;", "&Oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&uuml;", "&yacute;", "&thorn;", "&yuml;", "&quot;", "&amp;", "&lt;", "&gt;", "&oelig;", "&oelig;", "&scaron;", "&scaron;", "&yuml;", "&circ;", "&tilde;", "&ensp;", "&emsp;", "&thinsp;", "&zwnj;", "&zwj;", "&lrm;", "&rlm;", "&ndash;", "&mdash;", "&lsquo;", "&rsquo;", "&sbquo;", "&ldquo;", "&rdquo;", "&bdquo;", "&dagger;", "&dagger;", "&permil;", "&lsaquo;", "&rsaquo;", "&euro;", "&fnof;", "&alpha;", "&beta;", "&gamma;", "&delta;", "&epsilon;", "&zeta;", "&eta;", "&theta;", "&iota;", "&kappa;", "&lambda;", "&mu;", "&nu;", "&xi;", "&omicron;", "&pi;", "&rho;", "&sigma;", "&tau;", "&upsilon;", "&phi;", "&chi;", "&psi;", "&omega;", "&alpha;", "&beta;", "&gamma;", "&delta;", "&epsilon;", "&zeta;", "&eta;", "&theta;", "&iota;", "&kappa;", "&lambda;", "&mu;", "&nu;", "&xi;", "&omicron;", "&pi;", "&rho;", "&sigmaf;", "&sigma;", "&tau;", "&upsilon;", "&phi;", "&chi;", "&psi;", "&omega;", "&thetasym;", "&upsih;", "&piv;", "&bull;", "&hellip;", "&prime;", "&prime;", "&oline;", "&frasl;", "&weierp;", "&image;", "&real;", "&trade;", "&alefsym;", "&larr;", "&uarr;", "&rarr;", "&darr;", "&harr;", "&crarr;", "&larr;", "&uarr;", "&rarr;", "&darr;", "&harr;", "&forall;", "&part;", "&exist;", "&empty;", "&nabla;", "&isin;", "&notin;", "&ni;", "&prod;", "&sum;", "&minus;", "&lowast;", "&radic;", "&prop;", "&infin;", "&ang;", "&and;", "&or;", "&cap;", "&cup;", "&int;", "&there4;", "&sim;", "&cong;", "&asymp;", "&ne;", "&equiv;", "&le;", "&ge;", "&sub;", "&sup;", "&nsub;", "&sube;", "&supe;", "&oplus;", "&otimes;", "&perp;", "&sdot;", "&lceil;", "&rceil;", "&lfloor;", "&rfloor;", "&lang;", "&rang;", "&loz;", "&spades;", "&clubs;", "&hearts;", "&diams;");
    var a = new Array("&#160;", "&#161;", "&#162;", "&#163;", "&#164;", "&#165;", "&#166;", "&#167;", "&#168;", "&#169;", "&#170;", "&#171;", "&#172;", "&#173;", "&#174;", "&#175;", "&#176;", "&#177;", "&#178;", "&#179;", "&#180;", "&#181;", "&#182;", "&#183;", "&#184;", "&#185;", "&#186;", "&#187;", "&#188;", "&#189;", "&#190;", "&#191;", "&#192;", "&#193;", "&#194;", "&#195;", "&#196;", "&#197;", "&#198;", "&#199;", "&#200;", "&#201;", "&#202;", "&#203;", "&#204;", "&#205;", "&#206;", "&#207;", "&#208;", "&#209;", "&#210;", "&#211;", "&#212;", "&#213;", "&#214;", "&#215;", "&#216;", "&#217;", "&#218;", "&#219;", "&#220;", "&#221;", "&#222;", "&#223;", "&#224;", "&#225;", "&#226;", "&#227;", "&#228;", "&#229;", "&#230;", "&#231;", "&#232;", "&#233;", "&#234;", "&#235;", "&#236;", "&#237;", "&#238;", "&#239;", "&#240;", "&#241;", "&#242;", "&#243;", "&#244;", "&#245;", "&#246;", "&#247;", "&#248;", "&#249;", "&#250;", "&#251;", "&#252;", "&#253;", "&#254;", "&#255;", "&#34;", "&#38;", "&#60;", "&#62;", "&#338;", "&#339;", "&#352;", "&#353;", "&#376;", "&#710;", "&#732;", "&#8194;", "&#8195;", "&#8201;", "&#8204;", "&#8205;", "&#8206;", "&#8207;", "&#8211;", "&#8212;", "&#8216;", "&#8217;", "&#8218;", "&#8220;", "&#8221;", "&#8222;", "&#8224;", "&#8225;", "&#8240;", "&#8249;", "&#8250;", "&#8364;", "&#402;", "&#913;", "&#914;", "&#915;", "&#916;", "&#917;", "&#918;", "&#919;", "&#920;", "&#921;", "&#922;", "&#923;", "&#924;", "&#925;", "&#926;", "&#927;", "&#928;", "&#929;", "&#931;", "&#932;", "&#933;", "&#934;", "&#935;", "&#936;", "&#937;", "&#945;", "&#946;", "&#947;", "&#948;", "&#949;", "&#950;", "&#951;", "&#952;", "&#953;", "&#954;", "&#955;", "&#956;", "&#957;", "&#958;", "&#959;", "&#960;", "&#961;", "&#962;", "&#963;", "&#964;", "&#965;", "&#966;", "&#967;", "&#968;", "&#969;", "&#977;", "&#978;", "&#982;", "&#8226;", "&#8230;", "&#8242;", "&#8243;", "&#8254;", "&#8260;", "&#8472;", "&#8465;", "&#8476;", "&#8482;", "&#8501;", "&#8592;", "&#8593;", "&#8594;", "&#8595;", "&#8596;", "&#8629;", "&#8656;", "&#8657;", "&#8658;", "&#8659;", "&#8660;", "&#8704;", "&#8706;", "&#8707;", "&#8709;", "&#8711;", "&#8712;", "&#8713;", "&#8715;", "&#8719;", "&#8721;", "&#8722;", "&#8727;", "&#8730;", "&#8733;", "&#8734;", "&#8736;", "&#8743;", "&#8744;", "&#8745;", "&#8746;", "&#8747;", "&#8756;", "&#8764;", "&#8773;", "&#8776;", "&#8800;", "&#8801;", "&#8804;", "&#8805;", "&#8834;", "&#8835;", "&#8836;", "&#8838;", "&#8839;", "&#8853;", "&#8855;", "&#8869;", "&#8901;", "&#8968;", "&#8969;", "&#8970;", "&#8971;", "&#9001;", "&#9002;", "&#9674;", "&#9824;", "&#9827;", "&#9829;", "&#9830;");
    return this.swapArrayVals(c, b, a)
  },
  NumericalToHTML: function(c) {
    var b = new Array("&#160;", "&#161;", "&#162;", "&#163;", "&#164;", "&#165;", "&#166;", "&#167;", "&#168;", "&#169;", "&#170;", "&#171;", "&#172;", "&#173;", "&#174;", "&#175;", "&#176;", "&#177;", "&#178;", "&#179;", "&#180;", "&#181;", "&#182;", "&#183;", "&#184;", "&#185;", "&#186;", "&#187;", "&#188;", "&#189;", "&#190;", "&#191;", "&#192;", "&#193;", "&#194;", "&#195;", "&#196;", "&#197;", "&#198;", "&#199;", "&#200;", "&#201;", "&#202;", "&#203;", "&#204;", "&#205;", "&#206;", "&#207;", "&#208;", "&#209;", "&#210;", "&#211;", "&#212;", "&#213;", "&#214;", "&#215;", "&#216;", "&#217;", "&#218;", "&#219;", "&#220;", "&#221;", "&#222;", "&#223;", "&#224;", "&#225;", "&#226;", "&#227;", "&#228;", "&#229;", "&#230;", "&#231;", "&#232;", "&#233;", "&#234;", "&#235;", "&#236;", "&#237;", "&#238;", "&#239;", "&#240;", "&#241;", "&#242;", "&#243;", "&#244;", "&#245;", "&#246;", "&#247;", "&#248;", "&#249;", "&#250;", "&#251;", "&#252;", "&#253;", "&#254;", "&#255;", "&#34;", "&#38;", "&#60;", "&#62;", "&#338;", "&#339;", "&#352;", "&#353;", "&#376;", "&#710;", "&#732;", "&#8194;", "&#8195;", "&#8201;", "&#8204;", "&#8205;", "&#8206;", "&#8207;", "&#8211;", "&#8212;", "&#8216;", "&#8217;", "&#8218;", "&#8220;", "&#8221;", "&#8222;", "&#8224;", "&#8225;", "&#8240;", "&#8249;", "&#8250;", "&#8364;", "&#402;", "&#913;", "&#914;", "&#915;", "&#916;", "&#917;", "&#918;", "&#919;", "&#920;", "&#921;", "&#922;", "&#923;", "&#924;", "&#925;", "&#926;", "&#927;", "&#928;", "&#929;", "&#931;", "&#932;", "&#933;", "&#934;", "&#935;", "&#936;", "&#937;", "&#945;", "&#946;", "&#947;", "&#948;", "&#949;", "&#950;", "&#951;", "&#952;", "&#953;", "&#954;", "&#955;", "&#956;", "&#957;", "&#958;", "&#959;", "&#960;", "&#961;", "&#962;", "&#963;", "&#964;", "&#965;", "&#966;", "&#967;", "&#968;", "&#969;", "&#977;", "&#978;", "&#982;", "&#8226;", "&#8230;", "&#8242;", "&#8243;", "&#8254;", "&#8260;", "&#8472;", "&#8465;", "&#8476;", "&#8482;", "&#8501;", "&#8592;", "&#8593;", "&#8594;", "&#8595;", "&#8596;", "&#8629;", "&#8656;", "&#8657;", "&#8658;", "&#8659;", "&#8660;", "&#8704;", "&#8706;", "&#8707;", "&#8709;", "&#8711;", "&#8712;", "&#8713;", "&#8715;", "&#8719;", "&#8721;", "&#8722;", "&#8727;", "&#8730;", "&#8733;", "&#8734;", "&#8736;", "&#8743;", "&#8744;", "&#8745;", "&#8746;", "&#8747;", "&#8756;", "&#8764;", "&#8773;", "&#8776;", "&#8800;", "&#8801;", "&#8804;", "&#8805;", "&#8834;", "&#8835;", "&#8836;", "&#8838;", "&#8839;", "&#8853;", "&#8855;", "&#8869;", "&#8901;", "&#8968;", "&#8969;", "&#8970;", "&#8971;", "&#9001;", "&#9002;", "&#9674;", "&#9824;", "&#9827;", "&#9829;", "&#9830;");
    var a = new Array("&nbsp;", "&iexcl;", "&cent;", "&pound;", "&curren;", "&yen;", "&brvbar;", "&sect;", "&uml;", "&copy;", "&ordf;", "&laquo;", "&not;", "&shy;", "&reg;", "&macr;", "&deg;", "&plusmn;", "&sup2;", "&sup3;", "&acute;", "&micro;", "&para;", "&middot;", "&cedil;", "&sup1;", "&ordm;", "&raquo;", "&frac14;", "&frac12;", "&frac34;", "&iquest;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&Auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&Ouml;", "&times;", "&oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&Uuml;", "&yacute;", "&thorn;", "&szlig;", "&agrave;", "&aacute;", "&acirc;", "&atilde;", "&auml;", "&aring;", "&aelig;", "&ccedil;", "&egrave;", "&eacute;", "&ecirc;", "&euml;", "&igrave;", "&iacute;", "&icirc;", "&iuml;", "&eth;", "&ntilde;", "&ograve;", "&oacute;", "&ocirc;", "&otilde;", "&ouml;", "&divide;", "&Oslash;", "&ugrave;", "&uacute;", "&ucirc;", "&uuml;", "&yacute;", "&thorn;", "&yuml;", "&quot;", "&amp;", "&lt;", "&gt;", "&oelig;", "&oelig;", "&scaron;", "&scaron;", "&yuml;", "&circ;", "&tilde;", "&ensp;", "&emsp;", "&thinsp;", "&zwnj;", "&zwj;", "&lrm;", "&rlm;", "&ndash;", "&mdash;", "&lsquo;", "&rsquo;", "&sbquo;", "&ldquo;", "&rdquo;", "&bdquo;", "&dagger;", "&dagger;", "&permil;", "&lsaquo;", "&rsaquo;", "&euro;", "&fnof;", "&alpha;", "&beta;", "&gamma;", "&delta;", "&epsilon;", "&zeta;", "&eta;", "&theta;", "&iota;", "&kappa;", "&lambda;", "&mu;", "&nu;", "&xi;", "&omicron;", "&pi;", "&rho;", "&sigma;", "&tau;", "&upsilon;", "&phi;", "&chi;", "&psi;", "&omega;", "&alpha;", "&beta;", "&gamma;", "&delta;", "&epsilon;", "&zeta;", "&eta;", "&theta;", "&iota;", "&kappa;", "&lambda;", "&mu;", "&nu;", "&xi;", "&omicron;", "&pi;", "&rho;", "&sigmaf;", "&sigma;", "&tau;", "&upsilon;", "&phi;", "&chi;", "&psi;", "&omega;", "&thetasym;", "&upsih;", "&piv;", "&bull;", "&hellip;", "&prime;", "&prime;", "&oline;", "&frasl;", "&weierp;", "&image;", "&real;", "&trade;", "&alefsym;", "&larr;", "&uarr;", "&rarr;", "&darr;", "&harr;", "&crarr;", "&larr;", "&uarr;", "&rarr;", "&darr;", "&harr;", "&forall;", "&part;", "&exist;", "&empty;", "&nabla;", "&isin;", "&notin;", "&ni;", "&prod;", "&sum;", "&minus;", "&lowast;", "&radic;", "&prop;", "&infin;", "&ang;", "&and;", "&or;", "&cap;", "&cup;", "&int;", "&there4;", "&sim;", "&cong;", "&asymp;", "&ne;", "&equiv;", "&le;", "&ge;", "&sub;", "&sup;", "&nsub;", "&sube;", "&supe;", "&oplus;", "&otimes;", "&perp;", "&sdot;", "&lceil;", "&rceil;", "&lfloor;", "&rfloor;", "&lang;", "&rang;", "&loz;", "&spades;", "&clubs;", "&hearts;", "&diams;");
    return this.swapArrayVals(c, b, a)
  },
  numEncode: function(b) {
    if (this.isEmpty(b)) {
      return ""
    }
    var d = "";
    for (var a = 0; a < b.length; a++) {
      var f = b.charAt(a);
      if (f < " " || f > "~") {
        f = "&#" + f.charCodeAt() + ";"
      }
      d += f
    }
    return d
  },
  htmlDecode: function(e) {
    var g, b, f = e;
    if (this.isEmpty(f)) {
      return ""
    }
    f = this.HTML2Numerical(f);
    arr = f.match(/&#[0-9]{1,5};/g);
    if (arr != null) {
      for (var a = 0; a < arr.length; a++) {
        b = arr[a];
        g = b.substring(2, b.length - 1);
        if (g >= -32768 && g <= 65535) {
          f = f.replace(b, String.fromCharCode(g))
        } else {
          f = f.replace(b, "")
        }
      }
    }
    return f
  },
  htmlEncode: function(a, b) {
    if (this.isEmpty(a)) {
      return ""
    }
    b = b | false;
    if (b) {
      if (this.EncodeType == "numerical") {
        a = a.replace(/&/g, "&#38;")
      } else {
        a = a.replace(/&/g, "&amp;")
      }
    }
    a = this.XSSEncode(a, false);
    if (this.EncodeType == "numerical" || !b) {
      a = this.HTML2Numerical(a)
    }
    a = this.numEncode(a);
    if (!b) {
      a = a.replace(/&#/g, "##AMPHASH##");
      if (this.EncodeType == "numerical") {
        a = a.replace(/&/g, "&#38;")
      } else {
        a = a.replace(/&/g, "&amp;")
      }
      a = a.replace(/##AMPHASH##/g, "&#")
    }
    a = a.replace(/&#\d*([^\d;]|$)/g, "$1");
    if (!b) {
      a = this.correctEncoding(a)
    }
    if (this.EncodeType == "entity") {
      a = this.NumericalToHTML(a)
    }
    return a
  },
  XSSEncode: function(b, a) {
    if (!this.isEmpty(b)) {
      a = a || true;
      if (a) {
        b = b.replace(/\'/g, "&#39;");
        b = b.replace(/\"/g, "&quot;");
        b = b.replace(/</g, "&lt;");
        b = b.replace(/>/g, "&gt;")
      } else {
        b = b.replace(/\'/g, "&#39;");
        b = b.replace(/\"/g, "&#34;");
        b = b.replace(/</g, "&#60;");
        b = b.replace(/>/g, "&#62;")
      }
      return b
    } else {
      return ""
    }
  },
  hasEncoded: function(a) {
    if (/&#[0-9]{1,5};/g.test(a)) {
      return true
    } else {
      if (/&[A-Z]{2,6};/gi.test(a)) {
        return true
      } else {
        return false
      }
    }
  },
  stripUnicode: function(a) {
    return a.replace(/[^\x20-\x7E]/g, "")
  },
  correctEncoding: function(a) {
    return a.replace(/(&amp;)(amp;)+/, "$1")
  },
  swapArrayVals: function(f, c, b) {
    if (this.isEmpty(f)) {
      return ""
    }
    var e;
    if (c && b) {
      if (c.length == b.length) {
        for (var a = 0, d = c.length; a < d; a++) {
          e = new RegExp(c[a], "g");
          f = f.replace(e, b[a])
        }
      }
    }
    return f
  },
  inArray: function(d, b) {
    for (var c = 0, a = b.length; c < a; c++) {
      if (b[c] === d) {
        return c
      }
    }
    return -1
  }
};

Encoder.htmlEncode('if (a < b && c > d) {} // Héllö naõ');
ready
Using replace with indexed array
var test = safe_tags_replace_indexed('if (a < b && c > d) {} // Héllö naõ');
ready
Using replace with switch
var test = safe_tags_replace_switch('if (a < b && c > d) {} // Héllö naõ');
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.