【问题标题】:What is the HtmlSpecialChars equivalent in JavaScript?JavaScript 中的 HtmlSpecialChars 等价物是什么?
【发布时间】:2009-11-24 01:59:20
【问题描述】:

显然,这比我想象的更难找到。它甚至是那么简单……

是否有与 PHP 的 htmlspecialchars 内置在 JavaScript 中的函数等效?我知道自己实现这一点相当容易,但使用内置函数(如果可用)会更好。

对于不熟悉 PHP 的人,htmlspecialchars 会将 <htmltag/> 之类的内容翻译成 <htmltag/>

我知道escape()encodeURI() 不能这样工作。

【问题讨论】:

  • php 有一些非常好的工具,var_dump、print_r、htmlspecialchars 等。不幸的是,我怀疑与 js 不一样。 js警报太差了。快速查看一些意外(并且在警告框中不可见)字符串即将到来的方法是警告字符串长度而不是字符串 itslef。

标签: javascript html escaping html-encode


【解决方案1】:

您的解决方案代码存在问题 - 它只会转义每个特殊字符的第一次出现。例如:

escapeHtml('Kip\'s <b>evil</b> "test" code\'s here');
Actual:   Kip&#039;s &lt;b&gt;evil</b> &quot;test" code's here
Expected: Kip&#039;s &lt;b&gt;evil&lt;/b&gt; &quot;test&quot; code&#039;s here

下面是正常工作的代码:

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

更新

下面的代码将产生与上面相同的结果,但它的性能更好,尤其是在大文本块上(感谢jbo5112)。

function escapeHtml(text) {
  var map = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#039;'
  };
  
  return text.replace(/[&<>"']/g, function(m) { return map[m]; });
}

【讨论】:

  • 这个函数的好处是它可以在默认情况下没有 dom 的 node.js 中工作
  • 使用单个替换和映射功能更快,并且单个替换的扩展性更好。 (jsperf.com/escape-html-special-chars/11)
  • @jbo5112 好点,我没有意识到 JS 允许回调替换。不过,这段代码更容易理解,我怀疑将 escapeHtml() 减少几毫秒会产生影响,除非你出于某种原因连续调用它数百次。
  • 这会扭曲文本中的 URL,使它们无法用于像 Autolinker.js 这样的插件。有什么办法可以解决这个问题?
  • @RadekMatěj 即使在这种情况下,在 HTML 文档中使用时,对两个 & 符号都进行编码是完全有效的(我认为这是最好的)。我仍然认为这是插件的错误。
【解决方案2】:

这就是 HTML 编码。没有原生的 javascript 函数可以做到这一点,但你可以谷歌并得到一些做得很好的。

例如http://sanzon.wordpress.com/2008/05/01/neat-little-html-encoding-trick-in-javascript/

编辑:
这是我测试过的:

var div = document.createElement('div');
  var text = document.createTextNode('<htmltag/>');
  div.appendChild(text);
  console.log(div.innerHTML);

输出:&amp;lt;htmltag/&amp;gt;

【讨论】:

  • 太糟糕了,那我只能使用自定义函数了。
  • 您可以尝试我在帖子中包含的链接中的方法。确实很简洁的概念。
  • @o.k.w:好的,首先你链接到这个:yuki-onna.co.uk/html/encode.html 这正是 encodeURIComponent 所做的,而不是 OP 所要求的。那你可以编辑吗?我似乎无法撤消我的 -1。
  • 是的,该页面的代码看起来合乎逻辑,但我没有测试它。新链接虽然有效,但我自己验证过。我已经在一段时间前更新了帖子。
  • @BeauCielBleu:不。创建的唯一节点是单个 div 元素和文本节点。使用文本`` 创建一个文本节点只会创建一个文本节点,而不是img 元素。
【解决方案3】:

值得一读: http://bigdingus.com/2007/12/29/html-escaping-in-javascript/

escapeHTML: (function() {
 var MAP = {
   '&': '&amp;',
   '<': '&lt;',
   '>': '&gt;',
   '"': '&#34;',
   "'": '&#39;'
 };
  var repl = function(c) { return MAP[c]; };
  return function(s) {
    return s.replace(/[&<>'"]/g, repl);
  };
})()

注意:只运行一次。并且不要在已经编码的字符串上运行它,例如&amp;amp;amp; 变为 &amp;amp;amp;

【讨论】:

  • 这应该是被接受且投票率最高的答案。我不确定为什么它没有投票。这是在 jsperf (jsperf.com/escape-html-special-chars/11) 上使用长(326KB Google 搜索结果)和短输入字符串的最快基准测试。请投票赞成。
  • 这个获得最高票数的答案有什么区别?为什么要附加内部功能?解释可以帮助用户更好地理解
【解决方案4】:

这是一个转义 HTML 的函数:

function escapeHtml(str)
{
    var map =
    {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#039;'
    };
    return str.replace(/[&<>"']/g, function(m) {return map[m];});
}

并解码:

function decodeHtml(str)
{
    var map =
    {
        '&amp;': '&',
        '&lt;': '<',
        '&gt;': '>',
        '&quot;': '"',
        '&#039;': "'"
    };
    return str.replace(/&amp;|&lt;|&gt;|&quot;|&#039;/g, function(m) {return map[m];});
}

【讨论】:

    【解决方案5】:

    使用 jQuery 可以是这样的:

    var escapedValue = $('<div/>').text(value).html();
    

    来自相关问题Escaping HTML strings with jQuery

    正如评论中提到的,双引号和单引号在此实现中保持原样。这意味着如果您需要将元素属性设为原始 html 字符串,则不应使用此解决方案。

    【讨论】:

    • 知道这是否有任何开销——向 DOM 添加一个虚拟对象?
    • 还有其他优势吗(比如,如果你有 unicode 字符或其他东西)?
    • 我发现了一些东西:双引号和单引号保持原样。如果您想在属性值中使用它,这会产生问题。
    • 对于小块文本,这需要运行所有替换的 30 倍。不过,它确实可以更好地扩展。使用像 Google 搜索结果页面 (326KB) 这样巨大的东西,它比替换或在直接 javascript 中执行此操作要快 25-30%。但是,它们都始终输给单个替换和映射功能。
    • 人们如何对这个答案进行投票:答案有 jquery:+1 - 不会转义单引号和双引号:ummmm ..(挠头).. +1。 &lt;!-- Caps rage begin --&gt; 这个答案应该是负分,因为它甚至没有接近回答“HtmlSpecialChars 等价物”的问题。 &lt;!-- Caps rage end --&gt; it-does-not-escape-quotes-jesus-christ-and -其他神。 OMG 你 jquery 人。
    【解决方案6】:

    Underscore.js为此提供了一个函数:

    _.escape(string)
    

    转义字符串以插入 HTML,替换 &、、" 和 ' 字符。

    http://underscorejs.org/#escape

    它不是内置的 JavaScript 函数,但如果您已经在使用 Underscore.js,如果要转换的字符串不太大,它比编写自己的函数更好。

    【讨论】:

    • _.escape(string) 也可以在 lodash 上使用
    • 为什么不能扩展?
    【解决方案7】:

    对此的另一种看法是完全放弃所有字符映射,而是将所有不需要的字符转换为它们各自的数字字符引用,例如:

    function escapeHtml(raw) {
        return raw.replace(/[&<>"']/g, function onReplace(match) {
            return '&#' + match.charCodeAt(0) + ';';
        });
    }
    

    注意,指定的 RegEx 仅处理 OP 想要转义的特定字符,但根据要使用转义 HTML 的上下文,这些字符可能不够用。 Ryan Grove 的文章There's more to HTML escaping than &, <, >, and " 是该主题的好读物。并且根据您的上下文,可能非常需要以下 RegEx 以避免 XSS 注入:

    var regex = /[&<>"'` !@$%()=+{}[\]]/g
    

    【讨论】:

      【解决方案8】:

      用途:

      String.prototype.escapeHTML = function() {
              return this.replace(/&/g, "&amp;")
                         .replace(/</g, "&lt;")
                         .replace(/>/g, "&gt;")
                         .replace(/"/g, "&quot;")
                         .replace(/'/g, "&#039;");
          }
      

      示例:

      var toto = "test<br>";
      alert(toto.escapeHTML());
      

      【讨论】:

      • 解释一下。例如,为什么正是这五个字符?选择它们背后的逻辑是什么?请通过editing your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来像是今天写的)。
      【解决方案9】:

      您可能不需要这样的功能。由于您的代码已经在浏览器中*,您可以直接访问 DOM,而不是生成和编码必须由浏览器向后解码才能实际使用的 HTML。

      使用innerText 属性将纯文本安全地插入到 DOM 中,并且比使用任何提供的转义函数快得多。甚至faster 也比将静态预编码字符串分配给innerHTML

      使用classList 编辑类,dataset 设置data- 属性,setAttribute 设置其他属性。

      所有这些都将为您处理转义。更准确地说,不需要转义,也不会在下面执行编码**,因为您正在处理 HTML,即 DOM 的文本表示。

      // use existing element
      var author = 'John "Superman" Doe <john@example.com>';
      var el = document.getElementById('first');
      el.dataset.author = author;
      el.textContent = 'Author: '+author;
      
      // or create a new element
      var a = document.createElement('a');
      a.classList.add('important');
      a.href = '/search?q=term+"exact"&n=50';
      a.textContent = 'Search for "exact" term';
      document.body.appendChild(a);
      
      // actual HTML code
      console.log(el.outerHTML);
      console.log(a.outerHTML);
      .important { color: red; }
      &lt;div id="first"&gt;&lt;/div&gt;

      * 此答案不适用于服务器端 JavaScript 用户(Node.js,etc.

      ** 除非您之后明确地将其转换为实际的 HTML。例如。通过访问innerHTML - 这就是您运行其他答案中建议的$('&lt;div/&gt;').text(value).html(); 时发生的情况。因此,如果您的最终目标是将一些数据插入到文档中,那么通过这种方式您将完成两次工作。您还可以看到,在生成的 HTML 中,并非所有内容都被编码,只有其有效所需的最小值。它是根据上下文完成的,这就是为什么这个 jQuery 方法不编码引号,因此不应该用作通用转义符。当您将 HTML 构造为字符串时,在属性值的位置使用不受信任或包含引号的数据时,需要引号转义。如果你使用 DOM API,你根本不用关心转义。

      【讨论】:

      • 谢谢!我花了很长时间寻找这样一个简单的解决方案。我发现的一件重要的事情是,如果您的文本包含换行符,那么您将不得不将它们替换为 HTML 换行符(类似于 el.textContent = str; el.innerHTML = el.innerHTML.replace(/\n/g, '&lt;br&gt;')),或者将 CSS white-space 属性设置为 pre 或 @987654338 @
      • @stellatedHexahedron,感谢您提出这个问题。我已将答案更改为推荐 innerText 而不是 textContent。虽然在读取属性时有点慢并且有一些other differences,但它更直观,因为它在分配给它时会自动替换&lt;br&gt;
      【解决方案10】:
      function htmlEscape(str){
          return str.replace(/[&<>'"]/g,x=>'&#'+x.charCodeAt(0)+';')
      }
      

      此方案使用字符的数字编码,例如&lt;替换为&amp;#60;

      虽然性能比the solution using a map略差,但有优势:

      • 不依赖于库或 DOM
      • 很容易记住(您不需要记住 5 个 HTML 转义字符)
      • 小代码
      • 相当快(它仍然比 5 链式替换快)

      【讨论】:

        【解决方案11】:

        书本

        OWASP recommends 表示“[e]除了字母数字字符,[您应该] 使用&amp;#xHH; 格式(或命名实体,如果可用)转义所有 ASCII 值小于 256 的字符,以防止切换出 [an ] 属性。”

        所以这里有一个函数可以做到这一点,并带有一个用法示例:

        function escapeHTML(unsafe) {
          return unsafe.replace(
            /[\u0000-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u00FF]/g,
            c => '&#' + ('000' + c.charCodeAt(0)).slice(-4) + ';'
          )
        }
        
        document.querySelector('div').innerHTML =
          '<span class=' +
          escapeHTML('"fakeclass" onclick="alert("test")') +
          '>' +
          escapeHTML('<script>alert("inspect the attributes")\u003C/script>') +
          '</span>'
        &lt;div&gt;&lt;/div&gt;

        您应该验证我提供的实体范围,以自己验证函数的安全性。你也可以使用这个正则表达式,它具有更好的可读性并且应该涵盖相同的字符代码,但在我的浏览器中性能降低了大约 10%:

        /(?![0-9A-Za-z])[\u0000-\u00FF]/g

        【讨论】:

          【解决方案12】:

          对于 Node.js 用户(或在浏览器中使用 Jade 运行时的用户),您可以使用 Jade 的转义功能。

          require('jade').runtime.escape(...);
          

          如果有人在维护它,那么自己编写它没有任何意义。 :)

          【讨论】:

            【解决方案13】:

            我正在详细说明o.k.w.'s answer

            您可以为此使用浏览器的 DOM 函数。

            var utils = {
                dummy: document.createElement('div'),
                escapeHTML: function(s) {
                    this.dummy.textContent = s
                    return this.dummy.innerHTML
                }
            }
            
            utils.escapeHTML('<escapeThis>&')
            

            这会返回&amp;lt;escapeThis&amp;gt;&amp;amp;

            它使用标准函数 createElement 创建一个不可见元素,然后使用函数 textContent 将任何字符串设置为其内容,然后使用 innerHTML 以 HTML 表示形式获取内容。

            【讨论】:

              【解决方案14】:
              function htmlspecialchars(str) {
               if (typeof(str) == "string") {
                str = str.replace(/&/g, "&amp;"); /* must do &amp; first */
                str = str.replace(/"/g, "&quot;");
                str = str.replace(/'/g, "&#039;");
                str = str.replace(/</g, "&lt;");
                str = str.replace(/>/g, "&gt;");
                }
               return str;
               }
              

              【讨论】:

                【解决方案15】:

                这与这个问题没有直接关系,但是可以通过以下方式在JS中完成相反的操作:

                > String.fromCharCode(8212);
                > "—"
                

                这也适用于 TypeScript。

                【讨论】:

                  【解决方案16】:

                  我希望这能赢得比赛,因为它的性能和最重要的不是使用 .replace('&','&').replace('

                  var mapObj = {
                     '&':  "&amp;",
                     '<':  "&lt;",
                     '>':  "&gt;",
                     '"':  "&quot;",
                     '\'': "&#039;"
                  };
                  var re = new RegExp(Object.keys(mapObj).join("|"), "gi");
                  
                  function escapeHtml(str)
                  {
                      return str.replace(re, function(matched)
                      {
                          return mapObj[matched.toLowerCase()];
                      });
                  }
                  
                  console.log('<script type="text/javascript">alert('Hello World');</script>');
                  console.log(escapeHtml('<script type="text/javascript">alert('Hello World');</script>'));
                  

                  【讨论】:

                    【解决方案17】:

                    倒转一:

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

                    【讨论】:

                    • 问题不在于如何解码实体。这与问题的要求相反。
                    • 这只会替换字符串中&amp;lt;&amp;gr;第一个 个实例。
                    • 这只会解码(非Unicode文档之外)必须转义的五个字符,它不会解码可能的字符被逃脱。
                    • 这里没有考虑分号何时可选的规则。
                    • 如果 HTML 显示:To write a greater than sign in HTML type &amp;amp;gt;,它将错误地显示 &amp;gt; 而不是 &amp;gt;
                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2018-08-11
                    • 2014-12-06
                    • 2011-04-23
                    • 2013-07-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多