HTML实体解码[重复]
Posted
技术标签:
【中文标题】HTML实体解码[重复]【英文标题】:HTML Entity Decode [duplicate] 【发布时间】:2011-08-13 09:27:50 【问题描述】:如何使用 javascript 或 JQuery 编码和解码 html 实体?
var varTitle = "Chris' corner";
我希望它是:
var varTitle = "Chris' corner";
【问题讨论】:
见this answer。似乎比下面提供的要好。 另见 ent 模块(在 npm 上!)github.com/substack/node-ent 我认为@ringø(哇,奇怪的用户名相似...)意味着链接到this answer @rinogo 我想this was the better answer。显然he lib 正是为此目的而设计的。您可能可以像这里的大多数答案一样使用自定义实现来保存几行代码,但它们都有某种限制。 更简洁的方式:***.com/a/64587244/9854149 【参考方案1】:Original author answer here.
这是我最喜欢的解码 HTML 字符的方式。使用这段代码的好处是标签也被保留了。
function decodeHtml(html)
var txt = document.createElement("textarea");
txt.innerHTML = html;
return txt.value;
示例:http://jsfiddle.net/k65s3/
输入:
Entity: Bad attempt at XSS:<script>alert('new\nline?')</script><br>
输出:
Entity: Bad attempt at XSS:<script>alert('new\nline?')</script><br>
【讨论】:
此方法适用于任何地方,即使 jquery 不可用或尚未加载,因为它是纯 javascript。 这种技术有什么缺点吗?这似乎比上面的答案容易得多。 @anthonygood 每次函数创建一个新对象(DOM 元素) 下次@insign 请注明原作者或提供链接。 ***.com/a/7394787 @geauser 是的,完成【参考方案2】:这是另一个版本:
function convertHTMLEntity(text)
const span = document.createElement('span');
return text
.replace(/&[#A-Za-z0-9]+;/gi, (entity,position,text)=>
span.innerHTML = entity;
return span.innerText;
);
console.log(convertHTMLEntity('Large < £ 500'));
【讨论】:
既然您同时匹配A-Z
和a-z
,是否需要不区分大小写的选项?
@tigrou 不,您可以删除该选项。
这是最好的版本谢谢!【参考方案3】:
你可以试试这样的:
var Title = $('<textarea />').html("Chris' corner").text();
console.log(Title);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
JS Fiddle.
更具互动性的版本:
$('form').submit(function()
var theString = $('#string').val();
var varTitle = $('<textarea />').html(theString).text();
$('#output').text(varTitle);
return false;
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form action="#" method="post">
<fieldset>
<label for="string">Enter a html-encoded string to decode</label>
<input type="text" name="string" id="string" />
</fieldset>
<fieldset>
<input type="submit" value="decode" />
</fieldset>
</form>
<div id="output"></div>
JS Fiddle.
【讨论】:
很酷。所以只是好奇,$('div />') 是用来在 varTitle 周围创建一个 元素的? @chris 和@david - 此代码创建一个空的(从 DOM 分离的)div 并将其设置为 innerHTML,最后作为普通文本检索回来。它不是用DIV包围它,而是把它放在一个div中。我强调这一点,因为了解 jQuery 的工作原理至关重要。 请勿将其用于不受信任的数据,请参阅此处 Mike 的评论:***.com/questions/1147359/… 只是插话。这很容易受到 xss 攻击,试试吧! ***.com/questions/31282274/… 这可能容易受到旧 jQuery 版本 (see more here) 的 XSS 攻击。我建议改用he library。您可以在另一个answer to similar question 中查看代码示例。【参考方案4】:@William Lahti 回答的更实用的方法:
var entities =
'amp': '&',
'apos': '\'',
'#x27': '\'',
'#x2F': '/',
'#39': '\'',
'#47': '/',
'lt': '<',
'gt': '>',
'nbsp': ' ',
'quot': '"'
function decodeHTMLEntities (text)
return text.replace(/&([^;]+);/gm, function (match, entity)
return entities[entity] || match
)
【讨论】:
这不能解决 decodeHTMLEntities('ä') 或 ä :) 的问题 该列表肯定不完整,它只是对已接受答案的重写。您可以在实体列表中添加任何您想要的内容,只需添加 '#228': 'ä'。 我认为为 ****** 千个特殊字符这样做可能意味着死亡:( 如果你需要支持所有字符,你是绝对正确的。正如我所说,这是对已接受答案的重写。 顺便说一句,这正是像我这样的人所需要的。我需要一个简短的列表,我可以设法将其放入 gatsby 实用程序中,其中文档不可用。完全防弹并不总是目标。【参考方案5】:这是一种不需要创建 div 并解码“最常见”的 HTML 转义字符的快速方法:
function decodeHTMLEntities(text)
var entities = [
['amp', '&'],
['apos', '\''],
['#x27', '\''],
['#x2F', '/'],
['#39', '\''],
['#47', '/'],
['lt', '<'],
['gt', '>'],
['nbsp', ' '],
['quot', '"']
];
for (var i = 0, max = entities.length; i < max; ++i)
text = text.replace(new RegExp('&'+entities[i][0]+';', 'g'), entities[i][1]);
return text;
【讨论】:
您的答案对于大多数 html 实体根本不起作用,并且将其扩展以包含它们将非常重复且容易出错。例如,每个日文汉字字符都有一个实体,其中有数千个。另外,到那时,如果您的答案比这里的其他人慢,我也不会感到惊讶,因为您将为每个要解码的字符串运行数千次替换和数千个正则表达式。 当你对这些字符串进行编码时,这真的取决于你的目的。如果您的目标是让它不通过 之类的东西触发 HTML 处理,则完全没有必要通过字符实体语法对其他字符进行编码。大量的字符实体主要用作便利工具。我列出的实体是您必须转义以避免数据与 HTML 混淆的最少实体。 [在下一条评论中继续] 至于速度方面,运行多个正则表达式的好处。但是,当然,由于您将每个字符实体放入该代码的想法是毫无意义的,坦率地说,真的很愚蠢,所以这不是问题。然而,可以使用 | 生成正则表达式。首先是字符并执行一次 replace() 调用。我认为您必须对其进行基准测试以查看哪个更快,但是我的直觉说使用起来会更快|由于 Javascript 中的函数调用开销很高,因此使用了一个 replace()。 对,所以您的解决方案不完整。 OP 从来没有说过他们为什么要编码他们的 HTML 实体,所以如果你在这方面做出假设,它可能应该在答案中注明。 当您尝试在 javascript 中复制 htmlspecialchars_decode 时,这就完成了。它不会假装复制 html_entity_decode。我发现这个话题有很多噪音,还有很多臃肿/不安全的方法。这是 Kip 和 Chris Jacob 提供的出色编码解决方案的解码伴侣:***.com/questions/1787322/…【参考方案6】:这里是完整版
function htmldecode(s)
window.HTML_ESC_MAP =
"nbsp":" ","iexcl":"¡","cent":"¢","pound":"£","curren":"¤","yen":"¥","brvbar":"¦","sect":"§","uml":"¨","copy":"©","ordf":"ª","laquo":"«","not":"¬","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":"ÿ","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":"♦","\"":"quot","amp":"&","lt":"<","gt":">","OElig":"Œ","oelig":"œ","Scaron":"Š","scaron":"š","Yuml":"Ÿ","circ":"ˆ","tilde":"˜","ndash":"–","mdash":"—","lsquo":"‘","rsquo":"’","sbquo":"‚","ldquo":"“","rdquo":"”","bdquo":"„","dagger":"†","Dagger":"‡","permil":"‰","lsaquo":"‹","rsaquo":"›","euro":"€";
if(!window.HTML_ESC_MAP_EXP)
window.HTML_ESC_MAP_EXP = new RegExp("&("+Object.keys(HTML_ESC_MAP).join("|")+");","g");
return s?s.replace(window.HTML_ESC_MAP_EXP,function(x)
return HTML_ESC_MAP[x.substring(1,x.length-1)]||x;
):s;
用法
htmldecode("∑ >€");
【讨论】:
小心nbsp char,我不得不手动替换它,因为这个例子使用的是普通空格。 像&#232;
这样的字符怎么样?【参考方案7】:
因为 @Robert K 和 @mattcasey 都有很好的代码,我想我会在这里贡献一个 CoffeeScript 版本,以防将来有人可以使用它:
String::unescape = (strict = false) ->
###
# Take escaped text, and return the unescaped version
#
# @param string str | String to be used
# @param bool strict | Stict mode will remove all HTML
#
# Test it here:
# https://jsfiddle.net/tigerhawkvok/t9pn1dn5/
#
# Code: https://gist.github.com/tigerhawkvok/285b8631ed6ebef4446d
###
# Create a dummy element
element = document.createElement("div")
decodeHTMLEntities = (str) ->
if str? and typeof str is "string"
unless strict is true
# escape HTML tags
str = escape(str).replace(/%26/g,'&').replace(/%23/g,'#').replace(/%3B/g,';')
else
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '')
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '')
element.innerHTML = str
if element.innerText
# Do we support innerText?
str = element.innerText
element.innerText = ""
else
# Firefox
str = element.textContent
element.textContent = ""
unescape(str)
# Remove encoded or double-encoded tags
fixHtmlEncodings = (string) ->
string = string.replace(/\&#/mg, '&#') # The rest, for double-encodings
string = string.replace(/\"/mg, '"')
string = string.replace(/\"e;/mg, '"')
string = string.replace(/\_/mg, '_')
string = string.replace(/\'/mg, "'")
string = string.replace(/\"/mg, '"')
string = string.replace(/\>/mg, '>')
string = string.replace(/\</mg, '<')
string
# Run it
tmp = fixHtmlEncodings(this)
decodeHTMLEntities(tmp)
参见https://jsfiddle.net/tigerhawkvok/t9pn1dn5/7/ 或https://gist.github.com/tigerhawkvok/285b8631ed6ebef4446d(包括已编译的 JS,与此答案相比可能已更新)
【讨论】:
【参考方案8】:受 Robert K 解决方案的启发,去除 html 标签并阻止执行脚本和事件处理程序,例如:<img src=fake onerror="prompt(1)">
在最新的 Chrome、FF、IE 上测试(应该可以在 IE9 上运行,但尚未测试)。
var decodeEntities = (function ()
//create a new html document (doesn't execute script tags in child elements)
var doc = document.implementation.createHTMLDocument("");
var element = doc.createElement('div');
function getText(str)
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
return str;
function decodeHTMLEntities(str)
if (str && typeof str === 'string')
var x = getText(str);
while (str !== x)
str = x;
x = getText(x);
return x;
return decodeHTMLEntities;
)();
只需调用:
decodeEntities('<img src=fake onerror="prompt(1)">');
decodeEntities("<script>alert('aaa!')</script>");
【讨论】:
【参考方案9】:我建议不要使用被接受为答案的 jQuery 代码。虽然它不会将要解码的字符串插入到页面中,但它确实会导致创建脚本和 HTML 元素等内容。这比我们需要的代码多得多。相反,我建议使用更安全、更优化的函数。
var decodeEntities = (function()
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
function decodeHTMLEntities (str)
if(str && typeof str === 'string')
// strip script/html tags
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
return str;
return decodeHTMLEntities;
)();
http://jsfiddle.net/LYteC/4/
要使用此函数,只需调用decodeEntities("&amp;")
,它将使用与 jQuery 版本相同的底层技术——但没有 jQuery 的开销,并且在清理输入中的 HTML 标记之后。请参阅Mike Samuel's comment 以了解如何过滤掉 HTML 标签。
通过在项目中添加以下行,可以轻松地将这个函数用作 jQuery 插件。
jQuery.decodeEntities = decodeEntities;
【讨论】:
谁能告诉我什么 str.replace(/]|"[^"]*"|'[^']*') *>/gmi, '');有吗? @PoeHaH 它去除了所有的html标签,包括开始和结束。 注意:在 IE8 中不支持 textContent,所以如果它仍然是您的目标浏览器之一,您必须找到另一个解决方案。我只是浪费了一个小时试图弄清楚这一点,因为我们需要专门解码实体以弥补另一个 IE8 错误。 小心取出 HTML 标签的那一行。您不应该将正则表达式与 HTML/XML 一起使用。 Bobince 多年来一直清楚这一点。 @Qix 我不完全理解这里的问题。 HTML/XML 当然不应该像人们经常做的那样“用正则表达式解析”。如果您要做的只是对其进行标记,那么 AFAIK 正则表达式正是一个理想的解决方案。除非我遗漏了什么,否则完全剥离标签不需要任何超出词法分析的东西,因此在这里超越正则表达式没有任何好处。【参考方案10】:要在列表中添加另一个“灵感来自 Robert K”,这里是另一个 安全 版本,它不会去除 HTML 标记。它不是通过 HTML 解析器运行整个字符串,而是仅提取实体并转换它们。
var decodeEntities = (function()
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
// regular expression matching HTML entities
var entity = /&(?:#x[a-f0-9]+|#[0-9]+|[a-z0-9]+);?/ig;
return function decodeHTMLEntities(str)
// find and replace all the html entities
str = str.replace(entity, function(m)
element.innerHTML = m;
return element.textContent;
);
// reset the value
element.textContent = '';
return str;
)();
【讨论】:
【参考方案11】:jQuery 提供了一种编码和解码 html 实体的方法。
如果你使用“
”标签,它会去掉所有的html。function htmlDecode(value)
return $("<div/>").html(value).text();
function htmlEncode(value)
return $('<div/>').text(value).html();
如果你使用“”标签,它将保留html标签。
function htmlDecode(value)
return $("<textarea/>").html(value).text();
function htmlEncode(value)
return $('<textarea/>').text(value).html();
【讨论】:
爱它,对我有用,在 Chrome 控制台中对其进行了测试,实际上 我也更喜欢这个解决方案。一种纯 JavaScript 方法是使用var div = document.createElement('div');
创建一个 div,然后设置 innerHTML
并将 innerText
设置为 unescape;反之亦然。【参考方案12】:
就像 Robert K 所说,不要使用 jQuery.html().text() 来解码 html 实体,因为它不安全,因为用户输入永远不应该访问 DOM。阅读 XSS 了解为什么这是不安全的。
请尝试使用 escape 和 unescape 方法附带的 Underscore.js utility-belt 库:
_.escape(string)
转义字符串以插入 HTML,替换 &amp;
、&lt;
、&gt;
、"
、`
和 '
字符。
_.escape('Curly, Larry & Moe');
=> "Curly, Larry & Moe"
_.unescape(string)
转义的反义词,将&amp;
、&lt;
、&gt;
、&quot;
、&#96;
和&#x27;
替换为未转义的对应项。
_.unescape('Curly, Larry & Moe');
=> "Curly, Larry & Moe"
要支持解码更多字符,只需复制下划线unescape 方法并在映射中添加更多字符即可。
【讨论】:
@chovy,使用最新的 Underscore.js 版本 >= 1.4.2 不会出现 TypeError。 我喜欢这个答案,因为它不需要 DOM,现在谁可以保证在编写 javascript 时访问 DOM API?不幸的是,它只适用于列出的实体,并留下 之类的东西。原封不动。 +1 用于使用源代码控制库,而不是从顶部堆栈溢出答案中复制和粘贴一些随机代码。如果只有 javascript 标准库有这些低级函数就好了。 请记住,它不会对编码的俄语或日语字符进行解码。例如ハローワールド -> ハローワールド 不能这样做_.unescape
仅适用于 a handful of values。所以像_.unescape('&raquo;')
这样的东西只会返回"&raquo;"
【参考方案13】:
要在不使用 jquery 或预定义所有内容的纯 javascript 中执行此操作,您可以通过元素 innerHTML 和 innerText(/textContent) 属性为所需的每个解码步骤循环编码的 html 字符串:
<html>
<head>
<title>For every decode step, cycle through innerHTML and innerText </title>
<script>
function decode(str)
var d = document.createElement("div");
d.innerHTML = str;
return typeof d.innerText !== 'undefined' ? d.innerText : d.textContent;
</script>
</head>
<body>
<script>
var encodedString = "<p>name</p><p><span style=\"font-size:xx-small;\">ajde</span></p><p><em>da</em></p>";
</script>
<input type=button onclick="document.body.innerHTML=decode(encodedString)"/>
</body>
</html>
【讨论】:
【参考方案14】:我认为这与所选择的解决方案完全相反。
var decoded = $("<div/>").text(encodedStr).html();
试试看:)
【讨论】:
这种方法不安全。您可以在将运行的encodedStr
中包含 JavaScript。使用 Robert K 的方法。【参考方案15】:
受 Robert K 解决方案的启发,此版本不去除 HTML 标签,并且同样安全。
var decode_entities = (function()
// Remove HTML Entities
var element = document.createElement('div');
function decode_HTML_entities (str)
if(str && typeof str === 'string')
// Escape HTML before decoding for HTML Entities
str = escape(str).replace(/%26/g,'&').replace(/%23/g,'#').replace(/%3B/g,';');
element.innerHTML = str;
if(element.innerText)
str = element.innerText;
element.innerText = '';
else
// Firefox support
str = element.textContent;
element.textContent = '';
return unescape(str);
return decode_HTML_entities;
)();
【讨论】:
那些escape()
和 unescape()
函数已被弃用。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…【参考方案16】:
我知道我玩游戏有点晚了,但我想我可以提供以下 sn-p 作为我如何使用 jQuery 解码 HTML 实体的示例:
var varTitleE = "Chris' corner";
var varTitleD = $("<div/>").html(varTitleE).text();
console.log(varTitleE + " vs. " + varTitleD);
不要忘记启动检查器/firebug 以查看控制台结果 - 或者只需将 console.log(...) 替换为 w/alert(...)
也就是说,这是我的控制台通过 Google Chrome 检查器读取的内容:
Chris' corner vs. Chris' corner
【讨论】:
【参考方案17】:如How to decode HTML entities using jQuery? 中所述,将不受信任的 HTML 注入页面是危险的。
另一种方法是使用 php 的 html_entity_decode(来自 http://phpjs.org/functions/html_entity_decode:424)的纯 JavaScript 实现。该示例将类似于:
var varTitle = html_entity_decode("Chris' corner");
【讨论】:
其实当前版本的html_entity_decode并没有处理'。以上是关于HTML实体解码[重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用 JavaScript (RegExp) 转换 HTML 实体 [重复]
在 CSS 内容中添加“黑色右指向指针”HTML 实体 [重复]