Unescape HTML сущности в JavaScript?

У меня есть некоторый код Javascript, который взаимодействует с бэкэндом XML-RPC. XML-RPC возвращает строки в форме:

<img src='myimage.jpg'>

Однако когда я использую Javascript для вставки строк в HTML, они отображаются буквально. Я не вижу изображения, я буквально вижу строку:

<img src='myimage.jpg'>

Я предполагаю, что HTML экранируется по каналу XML-RPC.

Как я могу удалить строку в Javascript? Я попробовал методы на этой странице, но безуспешно: http://paulschreiber.com/blog/2008/09/20/javascript-how-to-unescape-html-entities/

Каковы другие способы диагностики проблемы?

23 ответа

Решение

Я использую следующий метод:

function htmlDecode(input){
  var e = document.createElement('div');
  e.innerHTML = input;
  // handle case of empty input
  return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}

htmlDecode("&lt;img src='myimage.jpg'&gt;"); 
// returns "<img src='myimage.jpg'>"

По сути, я создаю элемент DOM программно, назначаю закодированный HTML-код его innerHTML и извлекаю nodeValue из текстового узла, созданного при вставке innerHTML. Поскольку он просто создает элемент, но никогда не добавляет его, HTML-код сайта не изменяется.

Он будет работать в кросс-браузерном режиме (включая старые браузеры) и принимать все объекты символов HTML.

РЕДАКТИРОВАТЬ: старая версия этого кода не работала на IE с пустыми вводами, как показано здесь на jsFiddle (представление в IE). Версия выше работает со всеми входами.

ОБНОВЛЕНИЕ: кажется, это не работает с большой строкой, и это также вводит уязвимость безопасности, см. Комментарии.

Большинство ответов, приведенных здесь, имеют огромный недостаток: если строка, которую вы пытаетесь преобразовать, не является доверенной, в результате вы получите уязвимость для межсайтового скриптинга (XSS). Для функции в принятом ответе учтите следующее:

htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");

Здесь строка содержит неэкранированный HTML-тег, поэтому вместо декодирования чего-либо htmlDecode Функция на самом деле будет запускать код JavaScript, указанный внутри строки.

Этого можно избежать, используя DOMParser, который поддерживается во всех современных браузерах:

function htmlDecode(input)
{
  var doc = new DOMParser().parseFromString(input, "text/html");
  return doc.documentElement.textContent;
}

// This returns "<img src='myimage.jpg'>"
htmlDecode("&lt;img src='myimage.jpg'&gt;");

// This returns ""
htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");

Эта функция гарантированно не запускает какой-либо код JavaScript как побочный эффект. Любые HTML-теги будут игнорироваться, будет возвращен только текстовый контент.

Примечание о совместимости: анализ HTML с DOMParser требуется как минимум Chrome 30, Firefox 12, Opera 17, Internet Explorer 10, Safari 7.1 или Microsoft Edge. Таким образом, все браузеры без поддержки уже прошли EOL, и по состоянию на 2017 год единственными, которые все еще можно увидеть в дикой природе, иногда являются старые версии Internet Explorer и Safari (обычно их все еще недостаточно, чтобы беспокоиться).

Если вы используете jQuery:

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

В противном случае используйте объект кодирования Strictly Software, который имеет превосходный htmlDecode() функция.

Хитрость заключается в том, чтобы использовать возможности браузера для декодирования специальных символов HTML, но не позволять браузеру выполнять результаты, как если бы это был фактический HTML... Эта функция использует регулярное выражение для идентификации и замены закодированных символов HTML, один символ вовремя.

function unescapeHtml(html) {
    var el = document.createElement('div');
    return html.replace(/\&[#0-9a-z]+;/gi, function (enc) {
        el.innerHTML = enc;
        return el.innerText
    });
}

Ответ CMS работает нормально, если только HTML-код, который вы хотите удалить, не очень длинный, длиннее 65536 символов. Потому что тогда в Chrome внутренний HTML разбивается на множество дочерних узлов, каждый длиной не более 65536, и вам нужно объединить их. Эта функция работает также для очень длинных строк:

function unencodeHtmlContent(escapedHtml) {
  var elem = document.createElement('div');
  elem.innerHTML = escapedHtml;
  var result = '';
  // Chrome splits innerHTML into many child nodes, each one at most 65536.
  // Whereas FF creates just one single huge child node.
  for (var i = 0; i < elem.childNodes.length; ++i) {
    result = result + elem.childNodes[i].nodeValue;
  }
  return result;
}

Смотрите этот ответ о innerHTML максимальная длина для получения дополнительной информации: /questions/13204929/ogranichenie-razmera-innerhtml/13204953#13204953

Чтобы отключить экранирование HTML-объектов * в JavaScript, вы можете использовать небольшую библиотеку html-escaper:npm install html-escaper

import {unescape} from 'html-escaper';

unescape('escaped string');

Или unescapeфункция из Lodash или Underscore, если вы ее используете.


*) обратите внимание, что эти функции охватывают не все объекты HTML, а только наиболее распространенные, т.е. &, <, >, ', ". Для того, чтобы все HTML экранирования в сущности вы можете использовать он библиотеку.

Ответ Криса приятный и элегантный, но он терпит неудачу, если значение не определено. Простое улучшение делает его твердым:

function htmlDecode(value) {
   return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
}

Добро пожаловать... просто мессенджер... все заслуги передаются на ourcodeworld.com, ссылка ниже.

window.htmlentities = {
        /**
         * Converts a string to its html characters completely.
         *
         * @param {String} str String with unescaped HTML characters
         **/
        encode : function(str) {
            var buf = [];

            for (var i=str.length-1;i>=0;i--) {
                buf.unshift(['&#', str[i].charCodeAt(), ';'].join(''));
            }

            return buf.join('');
        },
        /**
         * Converts an html characterSet into its original character.
         *
         * @param {String} str htmlSet entities
         **/
        decode : function(str) {
            return str.replace(/&#(\d+);/g, function(match, dec) {
                return String.fromCharCode(dec);
            });
        }
    };

Полный кредит: https://ourcodeworld.com/articles/read/188/encode-and-decode-html-entities-using-pure-javascript

В вопросе не указано происхождение xно имеет смысл по возможности защищаться от злонамеренного (или просто неожиданного, со стороны нашего собственного приложения) ввода. Например, предположимx имеет ценность &amp; <script>alert('hello');</script>. Безопасный и простой способ справиться с этим в jQuery:

var x    = "&amp; <script>alert('hello');</script>";
var safe = $('<div />').html(x).text();

// => "& alert('hello');"

Найдено через https://gist.github.com/jmblog/3222899. Я не вижу многих причин избегать использования этого решения, поскольку оно как минимум такое же короткое, если не короче, чем некоторые альтернативы, и обеспечивает защиту от XSS.

(Изначально я разместил это как комментарий, но добавляю его как ответ, так как последующий комментарий в том же потоке потребовал, чтобы я это сделал).

Не прямой ответ на ваш вопрос, но не лучше ли вашему RPC вернуть некоторую структуру (будь то XML, JSON или что-то еще) с этими данными изображения (URL в вашем примере) внутри этой структуры?

Тогда вы можете просто разобрать его в своем JavaScript и построить <img> используя сам Javascript.

Структура, которую вы получаете от RPC, может выглядеть так:

{"img" : ["myimage.jpg", "myimage2.jpg"]}

Я думаю, что так будет лучше, поскольку внедрение кода, полученного из внешнего источника, на вашу страницу не выглядит очень безопасным. Представьте, что кто-то захватывает ваш XML-RPC-скрипт и помещает туда что-то, что вам не нужно (даже некоторый javascript...)

Я был достаточно сумасшедшим, чтобы пройти и сделать эту функцию, которая должна быть довольно, если не полностью, исчерпывающей:

function removeEncoding(string) {
    return string.replace(/&Agrave;/g, "À").replace(/&Aacute;/g, "Á").replace(/&Acirc;/g, "Â").replace(/&Atilde;/g, "Ã").replace(/&Auml;/g, "Ä").replace(/&Aring;/g, "Å").replace(/&agrave;/g, "à").replace(/&acirc;/g, "â").replace(/&atilde;/g, "ã").replace(/&auml;/g, "ä").replace(/&aring;/g, "å").replace(/&AElig;/g, "Æ").replace(/&aelig;/g, "æ").replace(/&szlig;/g, "ß").replace(/&Ccedil;/g, "Ç").replace(/&ccedil;/g, "ç").replace(/&Egrave;/g, "È").replace(/&Eacute;/g, "É").replace(/&Ecirc;/g, "Ê").replace(/&Euml;/g, "Ë").replace(/&egrave;/g, "è").replace(/&eacute;/g, "é").replace(/&ecirc;/g, "ê").replace(/&euml;/g, "ë").replace(/&#131;/g, "ƒ").replace(/&Igrave;/g, "Ì").replace(/&Iacute;/g, "Í").replace(/&Icirc;/g, "Î").replace(/&Iuml;/g, "Ï").replace(/&igrave;/g, "ì").replace(/&iacute;/g, "í").replace(/&icirc;/g, "î").replace(/&iuml;/g, "ï").replace(/&Ntilde;/g, "Ñ").replace(/&ntilde;/g, "ñ").replace(/&Ograve;/g, "Ò").replace(/&Oacute;/g, "Ó").replace(/&Ocirc;/g, "Ô").replace(/&Otilde;/g, "Õ").replace(/&Ouml;/g, "Ö").replace(/&ograve;/g, "ò").replace(/&oacute;/g, "ó").replace(/&ocirc;/g, "ô").replace(/&otilde;/g, "õ").replace(/&ouml;/g, "ö").replace(/&Oslash;/g, "Ø").replace(/&oslash;/g, "ø").replace(/&#140;/g, "Œ").replace(/&#156;/g, "œ").replace(/&#138;/g, "Š").replace(/&#154;/g, "š").replace(/&Ugrave;/g, "Ù").replace(/&Uacute;/g, "Ú").replace(/&Ucirc;/g, "Û").replace(/&Uuml;/g, "Ü").replace(/&ugrave;/g, "ù").replace(/&uacute;/g, "ú").replace(/&ucirc;/g, "û").replace(/&uuml;/g, "ü").replace(/&#181;/g, "µ").replace(/&#215;/g, "×").replace(/&Yacute;/g, "Ý").replace(/&#159;/g, "Ÿ").replace(/&yacute;/g, "ý").replace(/&yuml;/g, "ÿ").replace(/&#176;/g, "°").replace(/&#134;/g, "†").replace(/&#135;/g, "‡").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&#177;/g, "±").replace(/&#171;/g, "«").replace(/&#187;/g, "»").replace(/&#191;/g, "¿").replace(/&#161;/g, "¡").replace(/&#183;/g, "·").replace(/&#149;/g, "•").replace(/&#153;/g, "™").replace(/&copy;/g, "©").replace(/&reg;/g, "®").replace(/&#167;/g, "§").replace(/&#182;/g, "¶").replace(/&Alpha;/g, "Α").replace(/&Beta;/g, "Β").replace(/&Gamma;/g, "Γ").replace(/&Delta;/g, "Δ").replace(/&Epsilon;/g, "Ε").replace(/&Zeta;/g, "Ζ").replace(/&Eta;/g, "Η").replace(/&Theta;/g, "Θ").replace(/&Iota;/g, "Ι").replace(/&Kappa;/g, "Κ").replace(/&Lambda;/g, "Λ").replace(/&Mu;/g, "Μ").replace(/&Nu;/g, "Ν").replace(/&Xi;/g, "Ξ").replace(/&Omicron;/g, "Ο").replace(/&Pi;/g, "Π").replace(/&Rho;/g, "Ρ").replace(/&Sigma;/g, "Σ").replace(/&Tau;/g, "Τ").replace(/&Upsilon;/g, "Υ").replace(/&Phi;/g, "Φ").replace(/&Chi;/g, "Χ").replace(/&Psi;/g, "Ψ").replace(/&Omega;/g, "Ω").replace(/&alpha;/g, "α").replace(/&beta;/g, "β").replace(/&gamma;/g, "γ").replace(/&delta;/g, "δ").replace(/&epsilon;/g, "ε").replace(/&zeta;/g, "ζ").replace(/&eta;/g, "η").replace(/&theta;/g, "θ").replace(/&iota;/g, "ι").replace(/&kappa;/g, "κ").replace(/&lambda;/g, "λ").replace(/&mu;/g, "μ").replace(/&nu;/g, "ν").replace(/&xi;/g, "ξ").replace(/&omicron;/g, "ο").replace(/&piρ;/g, "ρ").replace(/&rho;/g, "ς").replace(/&sigmaf;/g, "ς").replace(/&sigma;/g, "σ").replace(/&tau;/g, "τ").replace(/&phi;/g, "φ").replace(/&chi;/g, "χ").replace(/&psi;/g, "ψ").replace(/&omega;/g, "ω").replace(/&bull;/g, "•").replace(/&hellip;/g, "…").replace(/&prime;/g, "′").replace(/&Prime;/g, "″").replace(/&oline;/g, "‾").replace(/&frasl;/g, "⁄").replace(/&weierp;/g, "℘").replace(/&image;/g, "ℑ").replace(/&real;/g, "ℜ").replace(/&trade;/g, "™").replace(/&alefsym;/g, "ℵ").replace(/&larr;/g, "←").replace(/&uarr;/g, "↑").replace(/&rarr;/g, "→").replace(/&darr;/g, "↓").replace(/&barr;/g, "↔").replace(/&crarr;/g, "↵").replace(/&lArr;/g, "⇐").replace(/&uArr;/g, "⇑").replace(/&rArr;/g, "⇒").replace(/&dArr;/g, "⇓").replace(/&hArr;/g, "⇔").replace(/&forall;/g, "∀").replace(/&part;/g, "∂").replace(/&exist;/g, "∃").replace(/&empty;/g, "∅").replace(/&nabla;/g, "∇").replace(/&isin;/g, "∈").replace(/&notin;/g, "∉").replace(/&ni;/g, "∋").replace(/&prod;/g, "∏").replace(/&sum;/g, "∑").replace(/&minus;/g, "−").replace(/&lowast;/g, "∗").replace(/&radic;/g, "√").replace(/&prop;/g, "∝").replace(/&infin;/g, "∞").replace(/&OEig;/g, "Œ").replace(/&oelig;/g, "œ").replace(/&Yuml;/g, "Ÿ").replace(/&spades;/g, "♠").replace(/&clubs;/g, "♣").replace(/&hearts;/g, "♥").replace(/&diams;/g, "♦").replace(/&thetasym;/g, "ϑ").replace(/&upsih;/g, "ϒ").replace(/&piv;/g, "ϖ").replace(/&Scaron;/g, "Š").replace(/&scaron;/g, "š").replace(/&ang;/g, "∠").replace(/&and;/g, "∧").replace(/&or;/g, "∨").replace(/&cap;/g, "∩").replace(/&cup;/g, "∪").replace(/&int;/g, "∫").replace(/&there4;/g, "∴").replace(/&sim;/g, "∼").replace(/&cong;/g, "≅").replace(/&asymp;/g, "≈").replace(/&ne;/g, "≠").replace(/&equiv;/g, "≡").replace(/&le;/g, "≤").replace(/&ge;/g, "≥").replace(/&sub;/g, "⊂").replace(/&sup;/g, "⊃").replace(/&nsub;/g, "⊄").replace(/&sube;/g, "⊆").replace(/&supe;/g, "⊇").replace(/&oplus;/g, "⊕").replace(/&otimes;/g, "⊗").replace(/&perp;/g, "⊥").replace(/&sdot;/g, "⋅").replace(/&lcell;/g, "⌈").replace(/&rcell;/g, "⌉").replace(/&lfloor;/g, "⌊").replace(/&rfloor;/g, "⌋").replace(/&lang;/g, "⟨").replace(/&rang;/g, "⟩").replace(/&loz;/g, "◊").replace(/&#039;/g, "'").replace(/&amp;/g, "&").replace(/&quot;/g, "\"");
}

Используется так:

let decodedText = removeEncoding("Ich hei&szlig;e David");
console.log(decodedText);

Печать: Ich Heiße David

PS это заняло около полутора часов.

Это наиболее полное решение, которое я пробовал до сих пор:

const STANDARD_HTML_ENTITIES = {
    nbsp: String.fromCharCode(160),
    amp: "&",
    quot: '"',
    lt: "<",
    gt: ">"
};

const replaceHtmlEntities = plainTextString => {
    return plainTextString
        .replace(/&#(\d+);/g, (match, dec) => String.fromCharCode(dec))
        .replace(
            /&(nbsp|amp|quot|lt|gt);/g,
            (a, b) => STANDARD_HTML_ENTITIES[b]
        );
};

Я знаю, что здесь есть много хороших ответов, но, поскольку я реализовал немного другой подход, я решил поделиться.

Этот код представляет собой совершенно безопасный подход с точки зрения безопасности, поскольку обработчик экранирования зависит от браузера, а не от функции. Таким образом, если в будущем будет обнаружена новая уязвимость, это решение будет покрыто.

      const decodeHTMLEntities = text => {
    // Create a new element or use one from cache, to save some element creation overhead
    const el = decodeHTMLEntities.__cache_data_element 
             = decodeHTMLEntities.__cache_data_element 
               || document.createElement('div');
    
    const enc = text
        // Prevent any mixup of existing pattern in text
        .replace(/⪪/g, '⪪#')
        // Encode entities in special format. This will prevent native element encoder to replace any amp characters
        .replace(/&([a-z1-8]{2,31}|#x[0-9a-f]+|#\d+);/gi, '⪪$1⪫');

    // Encode any HTML tags in the text to prevent script injection
    el.textContent = enc;

    // Decode entities from special format, back to their original HTML entities format
    el.innerHTML = el.innerHTML
        .replace(/⪪([a-z1-8]{2,31}|#x[0-9a-f]+|#\d+)⪫/gi, '&$1;')
        .replace(/#⪫/g, '⪫');
   
    // Get the decoded HTML entities
    const dec = el.textContent;
    
    // Clear the element content, in order to preserve a bit of memory (it is just the text may be pretty big)
    el.textContent = '';

    return dec;
}

// Example
console.log(decodeHTMLEntities("<script>alert('&awconint;&CounterClockwiseContourIntegral;&#x02233;&#8755;⪪#x02233⪫');</script>"));
// Prints: <script>alert('∳∳∳∳⪪##x02233⪫');</script>

Кстати, я решил использовать символы а также , потому что они используются редко, поэтому вероятность влияния на производительность путем их сопоставления значительно ниже.

Это лучше:

String::decode = ->
   $('<textarea />').html(this).text()

использовать:

"&lt;img src='myimage.jpg'&gt;".decode();

от: HTML Entity Decode

Замыкания позволяют избежать создания ненужных объектов.

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => {
    element.innerHTML = text;
    return element.textContent;
  };
})();

Более лаконичный способ

const decodingHandler = (() => {
  const element = document.createElement('div');
  return text => ((element.innerHTML = text), element.textContent);
})();

Используйте идентичность! Ни один из приведенных выше ответов меня не удовлетворил, поэтому я выбрал некоторые вещи отсюда, исправил их проблемы и добавил полные определения сущностей W3C, а также некоторые дополнительные функции. Я также сделал его как можно меньшим: теперь он составляет 31 КБ в минифицированном виде и 14 КБ в сжатом виде. Вы можете скачать его с https://github.com/arashkazemi/dentity .

Он включает в себя функции декодера и кодировщика и работает как в браузере, так и в среде узла. Надеюсь, это эффективно решит проблему!

Я использую это в своем проекте: вдохновленный другими ответами, но с дополнительным безопасным параметром, может быть полезен, когда вы имеете дело с украшенными персонажами

var decodeEntities=(function(){

    var el=document.createElement('div');
    return function(str, safeEscape){

        if(str && typeof str === 'string'){

            str=str.replace(/\</g, '&lt;');

            el.innerHTML=str;
            if(el.innerText){

                str=el.innerText;
                el.innerText='';
            }
            else if(el.textContent){

                str=el.textContent;
                el.textContent='';
            }

            if(safeEscape)
                str=str.replace(/\</g, '&lt;');
        }
        return str;
    }
})();

И это можно использовать как:

var label='safe <b> character &eacute;ntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';

Все остальные ответы здесь имеют проблемы.

Методы document.createElement('div') (включая методы, использующие jQuery) выполняют любой переданный в него javascript (проблема безопасности), а метод DOMParser.parseFromString() удаляет пробелы. Вот чистое решение JavaScript, которое не имеет ни одной проблемы:

function htmlDecode(html) {
    var textarea = document.createElement("textarea");
    html= html.replace(/\r/g, String.fromCharCode(0xe000)); // Replace "\r" with reserved unicode character.
    textarea.innerHTML = html;
    var result = textarea.value;
    return result.replace(new RegExp(String.fromCharCode(0xe000), 'g'), '\r');
}

TextArea используется специально, чтобы избежать выполнения кода JS. Это проходит эти:

htmlDecode('&lt;&amp;&nbsp;&gt;'); // returns "<& >" with non-breaking space.
htmlDecode('  '); // returns "  "
htmlDecode('<img src="dummy" onerror="alert(\'xss\')">'); // Does not execute alert()
htmlDecode('\r\n') // returns "\r\n", doesn't lose the \r like other solutions.
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);
      // decode-html.js v1
function decodeHtml(html) {
    const textarea = document.createElement('textarea');
    textarea.innerHTML = html;
    const decodedHtml = textarea.textContent;
    textarea.remove();
    return decodedHtml;
};

// encode-html.js v1
function encodeHtml(html) {
    const textarea = document.createElement('textarea');
    textarea.textContent = html;
    const encodedHtml = textarea.innerHTML;
    textarea.remove();
    return encodedHtml;
};

// example of use:
let htmlDecoded = 'one & two & three';
let htmlEncoded = 'one &amp; two &amp; three';

console.log(1, htmlDecoded);
console.log(2, encodeHtml(htmlDecoded));

console.log(3, htmlEncoded);
console.log(4, decodeHtml(htmlEncoded));

function decodeHTMLContent(htmlText) {
  var txt = document.createElement("span");
  txt.innerHTML = htmlText;
  return txt.innerText;
}

var result = decodeHTMLContent('One &amp; two &amp; three');
console.log(result);

Есть вариант, который на 80% продуктивнее ответов на самом верху.

См. Тест: https://jsperf.com/decode-html12345678/1

тест производительности

console.log(decodeEntities('test: &gt'));

function decodeEntities(str) {
  // this prevents any overhead from creating the object each time
  const el = decodeEntities.element || document.createElement('textarea')

  // strip script/html tags
  el.innerHTML = str
    .replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
    .replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');

  return el.value;
}

Если вам нужно оставить метки, то удалите два .replace(...) звонки (вы можете оставить первый, если вам не нужны скрипты).

Текущий ответ с наибольшим количеством голосов имеет тот недостаток, что он удаляет HTML из строки. Если это не то, что вы хотите (это, конечно, не было частью вопроса), я предлагаю использовать регулярное выражение для поиска объектов HTML (/&[^;]*;/gmi), а затем перебирать совпадения и просто преобразовывать их.

Что касается XSS-атак:

ПокаinnerHTMLне выполняет код в<script>теги, код может выполняться вon*атрибуты события, поэтому одно только приведенное выше регулярное выражение может быть использовано пользователем, передающим строку, например:

      &<img src='asdfa' error='alert(`doin\' me a hack`)' />;

По этой причине необходимо преобразовать любой<персонажей к их&lt;прежде чем помещать их в скрытый элемент div.

Кроме того, просто чтобы охватить все мои основы, я отмечу, что функции, определенные таким образом, в глобальной области видимости могут быть перезаписаны путем переопределения их в консоли, поэтому важно либо определить эту функцию с помощьюconstили поместите его в неглобальную область.

Примечание. Попытки эксплойта в следующем примере сбивают с толку редактор фрагментов стека из-за выполняемой им предварительной обработки, поэтому вам придется запускать его в консоли браузера или в его собственном файле, чтобы увидеть результат.

      var tests = [
  "here's a spade: &spades;!",
  "&<script>alert('hackerman')</script>;",
  "&<img src='asdfa' error='alert(`doin\' me a hack`)' />;",
  "<b>&#8593; &#67;&#65;&#78;'&#84;&nbsp;&#72;&#65;&#67;&#75;&nbsp;&#77;&#69;,&nbsp;&#66;&#82;&#79;</b>"
];

var decoded = tests.map(decodeHTMLEntities).join("\n");
console.log(decoded);

Результат:

      here's a spade: ♠!
&<script>alert('hackerman')</script>;
&<img src='asdfa' error='alert(`doin' me a hack`)' />;
<b>↑ CAN'T HACK ME, BRO</b>
Другие вопросы по тегам