在 JavaScript 中转义 HTML 实体?
Posted
技术标签:
【中文标题】在 JavaScript 中转义 HTML 实体?【英文标题】:Unescape HTML entities in JavaScript? 【发布时间】:2010-12-27 02:49:23 【问题描述】:我有一些与 XML-RPC 后端通信的 javascript 代码。 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/
还有哪些其他方法可以诊断问题?
【问题讨论】:
本文中包含的巨大功能似乎可以正常工作:blogs.msdn.com/b/aoakley/archive/2003/11/12/49645.aspx 我认为这不是最聪明的解决方案,但确实有效。 由于包含 HTML 实体的字符串与escape
d 或 URI encoded strings 不同,因此这些函数将不起作用。
@Matias 注意到自该函数于 2003 年创建以来,新的命名实体已添加到 HTML(例如通过 HTML 5 规范)——例如,它无法识别 &zopf;
。这是一个不断发展的规范的问题;因此,您应该选择一个实际维护的工具来解决它。
How to decode HTML entities using jQuery?的可能重复
我刚刚意识到将这个问题与编码 HTML 实体混淆是多么容易。我刚刚意识到我不小心在这个问题上发布了错误问题的答案!不过我已经删除了。
【参考方案1】:
编辑:你应该使用 DOMParser API 作为Wladimir suggests,我编辑了我之前的答案,因为发布的函数引入了一个安全漏洞。
以下 sn-p 是旧答案的代码,稍作修改:使用textarea
而不是div
减少了 XSS 漏洞,但在 IE9 和 Firefox 中仍然存在问题。
function htmlDecode(input)
var e = document.createElement('textarea');
e.innerHTML = input;
// handle case of empty input
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
htmlDecode("<img src='myimage.jpg'>");
// returns "<img src='myimage.jpg'>"
基本上,我以编程方式创建一个 DOM 元素,将编码的 HTML 分配给它的 innerHTML,并从在 innerHTML 插入时创建的文本节点中检索 nodeValue。由于它只是创建一个元素但从不添加它,因此不会修改网站 HTML。
它将跨浏览器(包括旧浏览器)工作并接受所有HTML Character Entities。
编辑:此代码的旧版本不适用于带有空白输入的 IE,如 here on jsFiddle 所示(在 IE 中查看)。以上版本适用于所有输入。
更新:似乎这不适用于大字符串,并且还引入了一个安全漏洞,请参阅 cmets。
【讨论】:
@S.Mark:&apos;
不属于 HTML 4 实体,这就是原因! w3.org/TR/html4/sgml/entities.htmlfishbowl.pastiche.org/2003/07/01/the_curse_of_apos
另请参阅@kender 关于此方法安全性差的说明。
请参阅我给@kender 的关于他所做的糟糕测试的说明;)
此函数存在安全隐患,即使元素未添加到 DOM,JavaScript 代码也会运行。所以这只有在输入字符串是可信的情况下才可以使用。我添加了my own answer,解释了这个问题并提供了一个安全的解决方案。作为副作用,如果存在多个文本节点,结果不会被截断。
如果 JS 没有在浏览器中运行,即使用 Node,这将不起作用。【参考方案2】:
不是对您的问题的直接回应,但是如果您的 RPC 返回一些结构(无论是 XML 还是 JSON 或其他)以及该结构中的那些图像数据(在您的示例中为 url),这不是更好吗?
然后你可以在你的javascript中解析它并使用javascript本身构建<img>
。
您从 RPC 收到的结构可能如下所示:
"img" : ["myimage.jpg", "myimage2.jpg"]
我认为这种方式更好,因为将来自外部源的代码注入您的页面看起来不太安全。想象有人劫持了您的 XML-RPC 脚本并在其中放入了您不想要的东西(甚至是一些 javascript...)
【讨论】:
上面的@CMS方法有这个安全漏洞吗? 我刚刚检查了传递给 htmlDecode 函数的以下参数: htmlDecode("<img src='myimage.jpg'><script>document.write('xxxxx');</ script>") 并且它创建了可能不好的 元素,恕我直言。而且我仍然认为返回结构而不是要插入的文本更好,例如,您可以很好地处理错误。 我刚试过htmlDecode("&lt;img src='myimage.jpg'&gt;&lt;script&gt;alert('xxxxx');&lt;/script&gt;")
,什么也没发生。我按预期得到了解码后的 html 字符串。【参考方案3】:
如果您使用的是 jQuery:
function htmlDecode(value)
return $('<div/>').html(value).text();
否则,使用Strictly Software's Encoder Object,它具有出色的htmlDecode()
功能。
【讨论】:
请勿(重复 NOT)将其用于用户生成的内容,而不是由 this 用户生成的内容。如果 value 中有 我在网站上的任何地方都找不到许可证。你知道许可证是什么吗? 源头中有一个许可证,它是 GPL。 是的,该函数为 XSS 开辟了道路:尝试 htmlDecode(" 123 >") $('')是什么意思?【参考方案4】:您需要解码所有编码的 HTML 实体还是只解码 &amp;
本身?
如果您只需要处理&amp;
,那么您可以这样做:
var decoded = encoded.replace(/&/g, '&');
如果您需要解码所有 HTML 实体,则无需 jQuery 即可:
var elem = document.createElement('textarea');
elem.innerHTML = encoded;
var decoded = elem.value;
请注意以下 Mark 的 cmets,其中突出显示了此答案早期版本中的安全漏洞,并建议使用 textarea
而不是 div
来缓解潜在的 XSS 漏洞。无论您使用 jQuery 还是纯 JavaScript,这些漏洞都存在。
【讨论】:
当心!这可能是不安全的。如果encoded='<img src="bla" onerror="alert(1)">'
则上面的 sn-p 将显示警报。这意味着如果您的编码文本来自用户输入,则使用此 sn-p 对其进行解码可能会出现 XSS 漏洞。
@MarkAmery 我不是安全专家,但看起来如果您在获取文本后立即将 div 设置为 null
,则不会触发 img 中的警报 - jsfiddle.net/Mottie/gaBeb/128跨度>
@Mottie 请注意确定哪个浏览器适合您,但在 OS X 上的 Chrome 上,alert(1)
仍然会为我触发。如果您想要此 hack 的安全变体,请尝试using a textarea
。
+1 用于简单的正则表达式替换仅一种 html 实体的替代方案。如果您希望将 html 数据从例如 python 烧瓶应用程序插入到模板中,请使用此选项。
如何在节点服务器上做到这一点?【参考方案5】:
Chris 的回答很好很优雅,但如果值为 undefined,它会失败。只需简单的改进就可以使其稳固:
function htmlDecode(value)
return (typeof value === 'undefined') ? '' : $('<div/>').html(value).text();
【讨论】:
如果要改进,那就做:return (typeof value !== 'string') ? '' : $('<div/>').html(value).text();
【参考方案6】:
element.innerText
也可以解决问题。
【讨论】:
【参考方案7】:首先在正文某处创建<span id="decodeIt" style="display:none;"></span>
接下来,将要解码为innerHTML的字符串赋值给这个:
document.getElementById("decodeIt").innerHTML=stringtodecode
最后,
stringtodecode=document.getElementById("decodeIt").innerText
这里是整体代码:
var stringtodecode="<B>Hello</B> world<br>";
document.getElementById("decodeIt").innerHTML=stringtodecode;
stringtodecode=document.getElementById("decodeIt").innerText
【讨论】:
-1;在不受信任的输入上使用这是非常不安全的。例如,考虑一下如果stringtodecode
包含类似<script>alert(1)</script>
的内容会发生什么。【参考方案8】:
var htmlEnDeCode = (function()
var charToEntityRegex,
entityToCharRegex,
charToEntity,
entityToChar;
function resetCharacterEntities()
charToEntity = ;
entityToChar = ;
// add the default set
addCharacterEntities(
'&' : '&',
'>' : '>',
'<' : '<',
'"' : '"',
''' : "'"
);
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
;
)();
这是来自 ExtJS 的源代码。
【讨论】:
-1;这无法处理绝大多数命名实体。例如,htmlEnDecode.htmlDecode('&euro;')
应该返回 '€'
,而是返回 '&euro;'
。【参考方案9】:
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
最大长度的答案:https://***.com/a/27545633/694469
【讨论】:
【参考方案10】:Matthias Bynens 为此提供了一个库:https://github.com/mathiasbynens/he
例子:
console.log(
he.decode("Jörg & Jürgen rocked to & fro ")
);
// Logs "Jörg & Jürgen rocked to & fro"
我建议使用它而不是涉及设置元素的 HTML 内容然后读回其文本内容的 hack。此类方法可行,但如果用于不受信任的用户输入,则具有欺骗性的危险性并会带来 XSS 机会。
如果你真的不忍心加载库,你可以使用this answer 中描述的textarea
hack 来解决一个几乎重复的问题,与建议的各种类似方法不同,它没有安全性我知道的漏洞:
function decodeEntities(encodedString)
var textArea = document.createElement('textarea');
textArea.innerHTML = encodedString;
return textArea.value;
console.log(decodeEntities('1 & 2')); // '1 & 2'
但请注意安全问题,影响与此类似的方法,我在链接的答案中列出!这种方法是一种 hack,未来对 textarea
允许内容的更改(或特定浏览器中的错误)可能会导致依赖它的代码有一天突然出现 XSS 漏洞。
【讨论】:
Matthias Bynens 的图书馆he
绝对很棒!非常感谢您的推荐!【参考方案11】:
这里给出的大多数答案都有一个巨大的缺点:如果您尝试转换的字符串不受信任,那么您最终会得到Cross-Site Scripting (XSS) vulnerability。对于accepted answer 中的函数,请考虑以下几点:
htmlDecode("<img src='dummy' onerror='alert(/xss/)'>");
这里的字符串包含一个未转义的 HTML 标记,因此htmlDecode
函数实际上将运行字符串中指定的 JavaScript 代码,而不是解码任何内容。
这可以通过使用DOMParser 来避免,all modern browsers 支持:
function htmlDecode(input)
var doc = new DOMParser().parseFromString(input, "text/html");
return doc.documentElement.textContent;
console.log( htmlDecode("<img src='myimage.jpg'>") )
// "<img src='myimage.jpg'>"
console.log( htmlDecode("<img src='dummy' onerror='alert(/xss/)'>") )
// ""
保证此函数不会运行任何 JavaScript 代码作为副作用。任何 HTML 标签都将被忽略,只返回文本内容。
兼容性说明:使用 DOMParser
解析 HTML 至少需要 Chrome 30、Firefox 12、Opera 17、Internet Explorer 10、Safari 7.1 或 Microsoft Edge。因此,所有不支持的浏览器都已超过其 EOL,并且截至 2017 年,偶尔仍能在野外看到的唯一浏览器是较旧的 Internet Explorer 和 Safari 版本(通常这些浏览器数量还不足以打扰)。
【讨论】:
我认为这个答案是最好的,因为它提到了 XSS 漏洞。 请注意(根据您的参考)DOMParser
在 Firefox 12.0 之前不支持 "text/html"
和 there are still some latest versions of browsers that do not even support DOMParser.prototype.parseFromString()
。根据您的参考,DOMParser
仍然是一项实验性技术,替代品使用innerHTML
属性,正如您在回复my approach 时也指出的那样,该属性存在此 XSS 漏洞(应该由浏览器供应商)。
@PointedEars:谁在乎 2016 年的 Firefox 12?有问题的是最高 9.0 的 Internet Explorer 和最高 7.0 的 Safari。如果一个人负担得起不支持它们(希望很快每个人都支持),那么 DOMParser 是最好的选择。如果不是 - 是的,只处理实体将是一种选择。
@PointedEars: <script>
标签不被执行不是一种安全机制,如果设置innerHTML
可以运行同步脚本作为副作用,此规则只是避免了棘手的时间问题。清理 HTML 代码是一件棘手的事情,innerHTML
甚至没有尝试过——因为网页实际上可能打算设置内联事件处理程序。这根本不是针对不安全数据的机制,句号。
@ИльяЗеленько:您是否打算在紧密循环中使用此代码,或者为什么性能很重要?你的回答又容易受到 XSS 的攻击,真的值得吗?【参考方案12】:
jQuery 将为您编码和解码。但是,您需要使用 textarea 标签,而不是 div。
var str1 = 'One & two & three';
var str2 = "One & two & 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();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<div id="encoded"></div>
<div id="decoded"></div>
【讨论】:
-1 因为旧 jQuery 版本存在(令人惊讶的)安全漏洞,其中一些可能仍然拥有重要的用户群——这些版本将在 HTML 中将 detect and explicitly evaluate scripts 传递给.html()
。因此,即使使用textarea
也不足以确保这里的安全性;我建议not using jQuery for this task and writing equivalent code with the plain DOM API。 (是的,jQuery 的旧行为既疯狂又可怕。)
感谢您指出这一点。但是,该问题不包括检查脚本注入的要求。该问题专门询问Web服务器呈现的html。保存到 Web 服务器的 Html 内容可能应该在保存之前进行脚本注入验证。【参考方案13】:
捕捉常见问题的 javascript 解决方案:
var map = amp: '&', lt: '<', gt: '>', quot: '"', '#039': "'"
str = str.replace(/&([^;]+);/g, (m, c) => map[c])
这是https://***.com/a/4835406/2738039的反面
【讨论】:
如果您使用map[c] || ''
,无法识别的将不会显示为undefined
覆盖范围非常有限; -1.
+1,更多的是unescapeHtml(str) var map = amp: '&', lt: '<', le: '≤', gt: '>', ge: '≥', quot: '"', '#039': "'" return str.replace(/&([^;]+);/g, (m, c) => map[c]|| '')
手动覆盖。不推荐。【参考方案14】:
从 JavaScript 解释 HTML(文本和其他)的更现代的选项是 DOMParser
API (see here in MDN) 中的 HTML 支持。这允许您使用浏览器的本机 HTML 解析器将字符串转换为 HTML 文档。自 2014 年底以来,所有主要浏览器的新版本都支持它。
如果我们只是想解码一些文本内容,我们可以将其作为文档正文中的唯一内容,解析文档,并提取其.body.textContent
。
var encodedStr = 'hello & world';
var parser = new DOMParser;
var dom = parser.parseFromString(
'<!doctype html><body>' + encodedStr,
'text/html');
var decodedString = dom.body.textContent;
console.log(decodedString);
我们可以在the draft specification for DOMParser
中看到解析后的文档没有启用 JavaScript,因此我们可以在没有安全问题的情况下执行此文本转换。
parseFromString(str, type)
方法必须运行这些步骤,具体取决于类型:
"text/html"
用
HTML parser
解析str,并返回新创建的Document
。脚本标志必须设置为“禁用”。
笔记
script
元素被标记为不可执行,noscript
的内容被解析为标记。
这超出了这个问题的范围,但是请注意如果您将解析后的 DOM 节点本身(不仅仅是它们的文本内容)移动到实时文档 DOM 中,这是可能的他们的脚本将被重新启用,并且可能存在安全问题。我没有研究过,所以请谨慎行事。
【讨论】:
NodeJs 的任何替代方案? @coderInrRain:he
, entities
and html-entities
【参考方案15】:
我在我的项目中使用它:灵感来自other answers,但带有一个额外的安全参数,在处理装饰字符时很有用
var decodeEntities=(function()
var el=document.createElement('div');
return function(str, safeEscape)
if(str && typeof str === 'string')
str=str.replace(/\</g, '<');
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, '<');
return str;
)();
它的用法如下:
var label='safe <b> character éntity</b>';
var safehtml='<div title="'+decodeEntities(label)+'">'+decodeEntities(label, true)+'</div>';
【讨论】:
【参考方案16】:对于单线的人:
const htmlDecode = innerHTML => Object.assign(document.createElement('textarea'), innerHTML).value;
console.log(htmlDecode('Complicated - Dimitri Vegas & Like Mike'));
【讨论】:
【参考方案17】:这里的所有其他答案都有问题。
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('<& >'); // 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.
【讨论】:
不,使用不同的标签不能解决问题。这仍然是一个 XSS 漏洞,试试htmlDecode("</textarea><img src=x onerror=alert(1)>")
。在我已经在 Sergio Belevskij 的回答中指出了这个问题之后,你发布了这个。
我无法重现您描述的问题。我在这个 JsFiddle 中有你的代码,运行时没有警报显示。 jsfiddle.net/edsjt15g/1可以看看吗?你用的是什么浏览器?
我正在使用 Firefox。 Chrome 确实以不同的方式处理这种情况,因此代码不会执行 - 但是你不应该依赖它。【参考方案18】:
诀窍是利用浏览器的强大功能来解码特殊的 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
);
【讨论】:
正则表达式可以与/\&#?[0-9a-z]+;/gi
匹配得更紧密一些,因为# 应该只作为第二个字符出现。
这是最好的答案。避免 XSS 漏洞,并且不去除 HTML 标签。【参考方案19】:
如果您正在寻找它,就像我一样 - 同时有一个不错且安全的 JQuery 方法。
https://api.jquery.com/jquery.parsehtml/
你可以 f.ex.在控制台中输入:
var x = "test &";
> undefined
$.parseHTML(x)[0].textContent
> "test &"
所以 $.parseHTML(x) 返回一个数组,如果你的文本中有 HTML 标记,array.length 将大于 1。
【讨论】:
非常适合我,这正是我想要的,谢谢。 如果x
的值为<script>alert('hello');</script>
,则上述内容将崩溃。在当前的 jQuery 中,它实际上不会尝试运行脚本,但[0]
将产生undefined
,因此对textContent
的调用将失败并且您的脚本将停在那里。 $('<div />').html(x).text();
看起来更安全 - 通过 gist.github.com/jmblog/3222899
@AndrewHodgkinson 是的,但问题是“在 JavaScript 中解码 & 返回 &” - 所以你要先测试 x 的内容,或者确保只在正确的情况下使用它。
我真的不明白这是怎么回事。上面的代码适用于所有情况。您将如何“确保” x 的值需要修复?如果上面的脚本示例警告“&”怎么办?所以它真的需要纠正吗?我们不知道 OP 的字符串来自哪里,因此必须考虑恶意输入。
@AndrewHodgkinson 我喜欢你的考虑,但这不是这里的问题。不过,请随意回答这个问题。我猜你可以删除脚本标签,f.ex.【参考方案20】:
你可以使用Lodash unescape / 转义函数https://lodash.com/docs/4.17.5#unescape
import unescape from 'lodash/unescape';
const str = unescape('fred, barney, & pebbles');
str 将变为'fred, barney, & pebbles'
【讨论】:
可能更好地执行“从'lodash/unescape'导入_unescape;”所以它不会与已弃用的同名javascript函数冲突:unescape【参考方案21】:我尝试了一切从 JSON 数组中删除 & 的方法。以上例子都没有,但https://***.com/users/2030321/chris 提供了一个很好的解决方案,让我解决了我的问题。
var stringtodecode="<B>Hello</B> world<br>";
document.getElementById("decodeIt").innerHTML=stringtodecode;
stringtodecode=document.getElementById("decodeIt").innerText
我没有使用,因为我不明白如何将其插入到将 JSON 数据拉入数组的模式窗口中,但我确实根据示例尝试过,并且成功了:
var modal = document.getElementById('demodal');
$('#ampersandcontent').text(replaceAll(data[0],"&", "&"));
我喜欢它,因为它很简单,而且很有效,但不知道为什么它没有被广泛使用。搜索 hi & low 以找到一个简单的解决方案。 我继续寻求对语法的理解,以及使用它是否有任何风险。还没有找到任何东西。
【讨论】:
您的第一个建议有点棘手,但不费吹灰之力就可以很好地工作。另一方面,第二个仅使用蛮力来解码字符。这意味着完成完整的解码功能可能需要大量的精力和时间。这就是为什么没有人使用这种方式来解决 OP 的问题。【参考方案22】:有一个变体,其效率与最顶部的答案一样高 80%。
查看基准:https://jsperf.com/decode-html12345678/1
console.log(decodeEntities('test: >'));
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(...)
调用(如果你不需要脚本,你可以留下第一个)。
【讨论】:
恭喜,您设法用虚假的清理逻辑掩盖了漏洞,所有这些都是为了在实践中取得无关紧要的性能胜利。尝试在 Firefox 中调用decodeEntities("</textarea '><img src=x onerror=alert(1) \">")
。请停止尝试使用正则表达式清理 HTML 代码。【参考方案23】:
不客气...只是一个信使...全部归功于 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
【讨论】:
这是一个不完整的解决方案;它只处理十进制数字字符引用,而不是命名字符引用或十六进制数字字符引用。【参考方案24】:var encodedStr = 'hello & world';
var parser = new DOMParser;
var dom = parser.parseFromString(
'<!doctype html><body>' + encodedStr,
'text/html');
var decodedString = dom.body.textContent;
console.log(decodedString);
【讨论】:
@Wladimir Palant(AdBlock Plus 的作者)之前已经给出了 DOMParser 的答案 4 years。您在发布之前阅读过之前的答案吗?【参考方案25】:我很疯狂地完成了这个应该很漂亮,如果不是完全,详尽的功能:
function removeEncoding(string)
return string.replace(/À/g, "À").replace(/Á/g, "Á").replace(/Â/g, "Â").replace(/Ã/g, "Ã").replace(/Ä/g, "Ä").replace(/Å/g, "Å").replace(/à/g, "à").replace(/â/g, "â").replace(/ã/g, "ã").replace(/ä/g, "ä").replace(/å/g, "å").replace(/Æ/g, "Æ").replace(/æ/g, "æ").replace(/ß/g, "ß").replace(/Ç/g, "Ç").replace(/ç/g, "ç").replace(/È/g, "È").replace(/É/g, "É").replace(/Ê/g, "Ê").replace(/Ë/g, "Ë").replace(/è/g, "è").replace(/é/g, "é").replace(/ê/g, "ê").replace(/ë/g, "ë").replace(/ƒ/g, "ƒ").replace(/Ì/g, "Ì").replace(/Í/g, "Í").replace(/Î/g, "Î").replace(/Ï/g, "Ï").replace(/ì/g, "ì").replace(/í/g, "í").replace(/î/g, "î").replace(/ï/g, "ï").replace(/Ñ/g, "Ñ").replace(/ñ/g, "ñ").replace(/Ò/g, "Ò").replace(/Ó/g, "Ó").replace(/Ô/g, "Ô").replace(/Õ/g, "Õ").replace(/Ö/g, "Ö").replace(/ò/g, "ò").replace(/ó/g, "ó").replace(/ô/g, "ô").replace(/õ/g, "õ").replace(/ö/g, "ö").replace(/Ø/g, "Ø").replace(/ø/g, "ø").replace(/Œ/g, "Œ").replace(/œ/g, "œ").replace(/Š/g, "Š").replace(/š/g, "š").replace(/Ù/g, "Ù").replace(/Ú/g, "Ú").replace(/Û/g, "Û").replace(/Ü/g, "Ü").replace(/ù/g, "ù").replace(/ú/g, "ú").replace(/û/g, "û").replace(/ü/g, "ü").replace(/µ/g, "µ").replace(/×/g, "×").replace(/Ý/g, "Ý").replace(/Ÿ/g, "Ÿ").replace(/ý/g, "ý").replace(/ÿ/g, "ÿ").replace(/°/g, "°").replace(/†/g, "†").replace(/‡/g, "‡").replace(/</g, "<").replace(/>/g, ">").replace(/±/g, "±").replace(/«/g, "«").replace(/»/g, "»").replace(/¿/g, "¿").replace(/¡/g, "¡").replace(/·/g, "·").replace(/•/g, "•").replace(/™/g, "™").replace(/©/g, "©").replace(/®/g, "®").replace(/§/g, "§").replace(/¶/g, "¶").replace(/Α/g, "Α").replace(/Β/g, "Β").replace(/Γ/g, "Γ").replace(/Δ/g, "Δ").replace(/Ε/g, "Ε").replace(/Ζ/g, "Ζ").replace(/Η/g, "Η").replace(/Θ/g, "Θ").replace(/Ι/g, "Ι").replace(/Κ/g, "Κ").replace(/Λ/g, "Λ").replace(/Μ/g, "Μ").replace(/Ν/g, "Ν").replace(/Ξ/g, "Ξ").replace(/Ο/g, "Ο").replace(/Π/g, "Π").replace(/Ρ/g, "Ρ").replace(/Σ/g, "Σ").replace(/Τ/g, "Τ").replace(/Υ/g, "Υ").replace(/Φ/g, "Φ").replace(/Χ/g, "Χ").replace(/Ψ/g, "Ψ").replace(/Ω/g, "Ω").replace(/α/g, "α").replace(/β/g, "β").replace(/γ/g, "γ").replace(/δ/g, "δ").replace(/ε/g, "ε").replace(/ζ/g, "ζ").replace(/η/g, "η").replace(/θ/g, "θ").replace(/ι/g, "ι").replace(/κ/g, "κ").replace(/λ/g, "λ").replace(/μ/g, "μ").replace(/ν/g, "ν").replace(/ξ/g, "ξ").replace(/ο/g, "ο").replace(/&piρ;/g, "ρ").replace(/ρ/g, "ς").replace(/ς/g, "ς").replace(/σ/g, "σ").replace(/τ/g, "τ").replace(/φ/g, "φ").replace(/χ/g, "χ").replace(/ψ/g, "ψ").replace(/ω/g, "ω").replace(/•/g, "•").replace(/…/g, "…").replace(/′/g, "′").replace(/″/g, "″").replace(/‾/g, "‾").replace(/⁄/g, "⁄").replace(/℘/g, "℘").replace(/ℑ/g, "ℑ").replace(/ℜ/g, "ℜ").replace(/™/g, "™").replace(/ℵ/g, "ℵ").replace(/←/g, "←").replace(/↑/g, "↑").replace(/→/g, "→").replace(/↓/g, "↓").replace(/&barr;/g, "↔").replace(/↵/g, "↵").replace(/⇐/g, "⇐").replace(/⇑/g, "⇑").replace(/⇒/g, "⇒").replace(/⇓/g, "⇓").replace(/⇔/g, "⇔").replace(/∀/g, "∀").replace(/∂/g, "∂").replace(/∃/g, "∃").replace(/∅/g, "∅").replace(/∇/g, "∇").replace(/∈/g, "∈").replace(/∉/g, "∉").replace(/∋/g, "∋").replace(/∏/g, "∏").replace(/∑/g, "∑").replace(/−/g, "−").replace(/∗/g, "∗").replace(/√/g, "√").replace(/∝/g, "∝").replace(/∞/g, "∞").replace(/&OEig;/g, "Œ").replace(/œ/g, "œ").replace(/Ÿ/g, "Ÿ").replace(/♠/g, "♠").replace(/♣/g, "♣").replace(/♥/g, "♥").replace(/♦/g, "♦").replace(/ϑ/g, "ϑ").replace(/ϒ/g, "ϒ").replace(/ϖ/g, "ϖ").replace(/Š/g, "Š").replace(/š/g, "š").replace(/∠/g, "∠").replace(/∧/g, "∧").replace(/∨/g, "∨").replace(/∩/g, "∩").replace(/∪/g, "∪").replace(/∫/g, "∫").replace(/∴/g, "∴").replace(/∼/g, "∼").replace(/≅/g, "≅").replace(/≈/g, "≈").replace(/≠/g, "≠").replace(/≡/g, "≡").replace(/≤/g, "≤").replace(/≥/g, "≥").replace(/⊂/g, "⊂").replace(/⊃/g, "⊃").replace(/⊄/g, "⊄").replace(/⊆/g, "⊆").replace(/⊇/g, "⊇").replace(/⊕/g, "⊕").replace(/⊗/g, "⊗").replace(/⊥/g, "⊥").replace(/⋅/g, "⋅").replace(/&lcell;/g, "⌈").replace(/&rcell;/g, "⌉").replace(/⌊/g, "⌊").replace(/⌋/g, "⌋").replace(/⟨/g, "⟨").replace(/⟩/g, "⟩").replace(/◊/g, "◊").replace(/'/g, "'").replace(/&/g, "&").replace(/"/g, "\"");
这样使用:
let decodedText = removeEncoding("Ich heiße David");
console.log(decodedText);
打印:Ich Heiße David
附:这花了大约一个半小时。
【讨论】:
不适用于"Ich Hei&#xDF;e David"
。【参考方案26】:
这是迄今为止我尝试过的最全面的解决方案:
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]
);
;
【讨论】:
“最全面”?您是否尝试过针对 actually comprehensive test suite 运行它?【参考方案27】:该问题没有指定x
的来源,但如果可以的话,防御恶意(或只是来自我们自己的应用程序的意外)输入是有意义的。例如,假设x
的值为&amp; <script>alert('hello');</script>
。在 jQuery 中处理此问题的一种安全且简单的方法是:
var x = "& <script>alert('hello');</script>";
var safe = $('<div />').html(x).text();
// => "& alert('hello');"
通过https://gist.github.com/jmblog/3222899 找到。我看不出有很多理由避免使用这个解决方案,因为它至少和一些替代方案一样短,如果不短的话并且提供对 XSS 的防御。
(我最初将此作为评论发布,但由于同一线程中的后续评论要求我这样做,因此我将其添加为答案)。
【讨论】:
【参考方案28】:function decodeHTMLContent(htmlText)
var txt = document.createElement("span");
txt.innerHTML = htmlText;
return txt.innerText;
var result = decodeHTMLContent('One & two & three');
console.log(result);
【讨论】:
这个答案比 年 前的textarea
好多少?
这将提出一个安全问题。没有什么能阻止您在其中添加 <img>
并运行任意 JS。 不要在生产中使用它或任何类似的东西(或用于业余项目,如果其他人会使用它)。【参考方案29】:
要在 JavaScript 中取消转义 HTML 实体*,您可以使用小型库 html-escaper: npm install html-escaper
import unescape from 'html-escaper';
unescape('escaped string');
或者unescape
函数来自Lodash或Underscore,如果你正在使用它。
*) 请注意,这些函数并未涵盖所有 HTML 实体,而仅涵盖最常见的实体,即&
、<
、>
、'
、"
。要取消转义所有 HTML 实体,您可以使用 he 库。
【讨论】:
【参考方案30】:闭包可以避免创建不必要的对象。
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);
)();
【讨论】:
以上是关于在 JavaScript 中转义 HTML 实体?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 XML 中转义 & 符号,以便将它们呈现为 HTML 中的实体?
我可以在 JavaScript 中转义 HTML 特殊字符吗?
我可以在 JavaScript 中转义 HTML 特殊字符吗?