解码& 回到JavaScript中

Art*_*Art 213 html javascript text decode

我有类似的字符串

var str = 'One & two & three';
Run Code Online (Sandbox Code Playgroud)

由Web服务器呈现为HTML.我需要将这些字符串转换为

'One & two & three'
Run Code Online (Sandbox Code Playgroud)

目前,这就是我正在做的事情(借助jQuery):

$(document.createElement('div')).html('{{ driver.person.name }}').text()
Run Code Online (Sandbox Code Playgroud)

但是我有一种不安的感觉,我做错了.我试过了

unescape("&")
Run Code Online (Sandbox Code Playgroud)

但它似乎不起作用,decodeURI/decodeURIComponent也没有.

有没有其他更原生和更优雅的方式呢?

Luk*_*keH 273

您是否需要解码所有已编码的HTML实体或仅解码它们&

如果您只需要处理,&那么您可以这样做:

var decoded = encoded.replace(/&/g, '&');
Run Code Online (Sandbox Code Playgroud)

如果你需要解码所有HTML实体,那么你可以在没有jQuery的情况下完成:

var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;
Run Code Online (Sandbox Code Playgroud)

请注意Mark下面的评论,其中突出显示了本答案早期版本中的安全漏洞,并建议使用textarea而不是div减轻潜在的XSS漏洞.无论您使用jQuery还是纯JavaScript,都存在这些漏洞.

  • 谨防!这可能是不安全的.如果`encoded ='<img rel="nofollow noreferrer" src ="bla"onerror ="alert(1)">'`,则上面的代码段会显示警告.这意味着如果您的编码文本来自用户输入,则使用此代码段对其进行解码可能会出现XSS漏洞. (16认同)
  • @Mottie请注意哪个浏览器适合你,但是`警告(1)`仍然会在OS X上的Chrome上为我开火.如果你想要这个黑客的安全变体,请尝试[使用`textarea`](http ://stackoverflow.com/a/31350391/1709587). (4认同)
  • 如何在 Node 服务器上执行此操作? (2认同)

小智 86

从JavaScript中解释HTML(文本和其他)的更现代的选项是DOMParserAPI中的HTML支持(参见MDN).这允许您使用浏览器的本机HTML解析器将字符串转换为HTML文档.自2014年底以来,它已在所有主流浏览器的新版本中得到支持.

如果我们只想解码一些文本内容,我们可以将其作为文档正文中的唯一内容,解析文档,然后将其删除.body.textContent.

var encodedStr = 'hello &amp; world';

var parser = new DOMParser;
var dom = parser.parseFromString(
    '<!doctype html><body>' + encodedStr,
    'text/html');
var decodedString = dom.body.textContent;

console.log(decodedString);
Run Code Online (Sandbox Code Playgroud)

我们可以在规范草案中DOMParser看到,未对已解析的文档启用JavaScript,因此我们可以在没有安全问题的情况下执行此文本转换.

parseFromString(str, type)方法必须运行以下步骤,具体取决于类型:

  • "text/html"

    解析海峡HTML parser,并返回新创建的Document.

    脚本标志必须设置为"禁用".

    注意

    script元素被标记为不可执行,并且get的内容noscript被解析为标记.

这超出了这个问题的范围,但请注意,如果你自己处理解析的DOM节点(不仅仅是他们的文本内容)并将它们移动到实时文档DOM,那么他们的脚本可能会被重新启用,并且可能会是安全问题.我没有研究过,所以请谨慎行事.

  • NodeJ的任何替代选择? (3认同)

Mar*_*ery 41

Matthias Bynens有一个图书馆:https://github.com/mathiasbynens/he

例:

console.log(
    he.decode("J&#246;rg &amp J&#xFC;rgen rocked to &amp; fro ")
);
// Logs "Jörg & Jürgen rocked to & fro"
Run Code Online (Sandbox Code Playgroud)

我建议赞成设置元素的HTML内容然后回读其文本内容.这些方法可以起作用,但是如果在不受信任的用户输入上使用,则存在欺骗性危险并呈现XSS机会.

如果你真的不忍心加载一个库,你可以使用这个答案中textarea描述的hack来解决一个近似重复的问题,这与我所建议的各种类似方法不同,我没有安全漏洞:

function decodeEntities(encodedString) {
    var textArea = document.createElement('textarea');
    textArea.innerHTML = encodedString;
    return textArea.value;
}

console.log(decodeEntities('1 &amp; 2')); // '1 & 2'
Run Code Online (Sandbox Code Playgroud)

但是请注意安全问题,影响这个问题的类似方法,我在链接的答案中列出!这种方法是一种黑客攻击,未来对a textarea(或特定浏览器中的错误)允许内容的更改可能会导致依赖于它的代码突然有一天出现XSS漏洞.


Wai*_*ung 23

var htmlEnDeCode = (function() {
    var charToEntityRegex,
        entityToCharRegex,
        charToEntity,
        entityToChar;

    function resetCharacterEntities() {
        charToEntity = {};
        entityToChar = {};
        // add the default set
        addCharacterEntities({
            '&amp;'     :   '&',
            '&gt;'      :   '>',
            '&lt;'      :   '<',
            '&quot;'    :   '"',
            '&#39;'     :   "'"
        });
    }

    function addCharacterEntities(newEntities) {
        var charKeys = [],
            entityKeys = [],
            key, echar;
        for (key in newEntities) {
            echar = newEntities[key];
            entityToChar[key] = echar;
            charToEntity[echar] = key;
            charKeys.push(echar);
            entityKeys.push(key);
        }
        charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
        entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
    }

    function htmlEncode(value){
        var htmlEncodeReplaceFn = function(match, capture) {
            return charToEntity[capture];
        };

        return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
    }

    function htmlDecode(value) {
        var htmlDecodeReplaceFn = function(match, capture) {
            return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
        };

        return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
    }

    resetCharacterEntities();

    return {
        htmlEncode: htmlEncode,
        htmlDecode: htmlDecode
    };
})();
Run Code Online (Sandbox Code Playgroud)

这是来自ExtJS的源代码.

  • -1; 这无法处理绝大多数命名实体.例如,`htmlEnDecode.htmlDecode('&euro;')`应返回'''',而是返回''&euro;'`. (3认同)

小智 16

element.innerText 也有诀窍.


csl*_*tty 12

如果你正在寻找它,像我一样 - 同时有一个很好的和安全的JQuery方法.

https://api.jquery.com/jquery.parsehtml/

你可以f.ex. 在您的控制台中键入:

var x = "test &amp;";
> undefined
$.parseHTML(x)[0].textContent
> "test &"
Run Code Online (Sandbox Code Playgroud)

因此$ .parseHTML(x)返回一个数组,如果你的文本中有HTML标记,则array.length将大于1.


I a*_*m L 12

您可以使用Lodash unescape /转义功能https://lodash.com/docs/4.17.5#unescape

import unescape from 'lodash/unescape';

const str = unescape('fred, barney, &amp; pebbles');
Run Code Online (Sandbox Code Playgroud)

str将成为 'fred, barney, & pebbles'

  • 可能更好地执行“import _unescape from 'lodash/unescape';” 所以它不会与已弃用的同名 javascript 函数冲突:unescape (2认同)

Jas*_*ams 8

jQuery将为您编码和解码.但是,您需要使用textarea标记,而不是div.

var str1 = 'One & two & three';
var str2 = "One &amp; two &amp; three";
  
$(document).ready(function() {
   $("#encoded").text(htmlEncode(str1)); 
   $("#decoded").text(htmlDecode(str2));
});

function htmlDecode(value) {
  return $("<textarea/>").html(value).text();
}

function htmlEncode(value) {
  return $('<textarea/>').text(value).html();
}
Run Code Online (Sandbox Code Playgroud)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>

<div id="encoded"></div>
<div id="decoded"></div>
Run Code Online (Sandbox Code Playgroud)

  • -1因为旧的jQuery版本存在(令人惊讶的)安全漏洞,其中一些可能仍然具有重要的用户群 - 这些版本将[*检测并显式评估脚本*](https://github.com/jquery/ jquery/blob/1.7/jquery.js#L6049)在HTML中传递给`.html()`.因此,即使使用"textarea"也不足以确保这里的安全性; 我建议[不使用jQuery执行此任务并使用普通DOM API编写等效代码](http://stackoverflow.com/a/1395954/1709587).(是的,jQuery的旧行为很疯狂而且非常糟糕.) (2认同)