在 JavaScript 中编码 HTML 实体

IT技术 javascript html
2021-01-26 16:01:26

我在一个允许用户输入内容的 CMS 中工作。问题是当他们添加符号时®,它可能无法在所有浏览器中很好地显示。我想设置一个必须搜索的符号列表,然后转换为相应的html实体。例如

® => ®
& => &
© => ©
™ =>™

转换后,需要包裹在一个<sup>标签中,结果如下:

® => <sup>&reg;</sup>

因为需要特定的字体大小和填充样式:

sup { font-size: 0.6em; padding-top: 0.2em; }

JavaScript 会是这样吗?

var regs = document.querySelectorAll('®');
  for ( var i = 0, l = imgs.length; i < l; ++i ) {
  var [?] = regs[i];
  var [?] = document.createElement('sup');
  img.parentNode.insertBefore([?]);
  div.appendChild([?]);
}

其中“[?]”表示有一些我不确定的事情。

额外细节:

  • 我想用纯 JavaScript 来做到这一点,而不是需要像 jQuery 这样的库,谢谢。
  • 后端是 Ruby
  • 使用由 Ruby on Rails 构建的 RefineryCMS
6个回答

您可以使用正则表达式将给定 unicode 范围内的任何字符替换为其等效的 html 实体。代码看起来像这样:

var encodedStr = rawStr.replace(/[\u00A0-\u9999<>\&]/g, function(i) {
   return '&#'+i.charCodeAt(0)+';';
});

与HTML表示,这简直就是-这个代码将取代在给定范围内的所有字符(9999,以及符号,更大和小于的unicode 00A0) &#nnn;其中nnn是Unicode值,我们从得到charCodeAt

在此处查看操作:http : //jsfiddle.net/E3EqX/13/(此示例使用 jQuery 作为示例中使用的元素选择器。上面的基本代码本身不使用 jQuery)

进行这些转换并不能解决所有问题——确保您使用的是 UTF8 字符编码,确保您的数据库以 UTF8 存储字符串。仍然可能会看到字符显示不正确的情况,具体取决于系统字体配置和您无法控制的其他问题。

文档

@Chris 感谢简洁的代码片段,尽管它确实有一个错误:“[\u00A0-\u99999]” 没有做你期望它做的事情,而是等于“[\u00A0-\u9999]|9 “ - IE。字符“9”也会被错误地替换为 HTML 实体。你也可以在小提琴中尝试。我会建议一个修复的答案。
2021-03-24 16:01:26
虽然我同意@mathias Bynens 的回答更完整,但他的解决方案是 84KB,这让我继续寻找替代方案。这看起来不错,但是还可以包括 charCodes < 65 和 >90 && <97 之间吗?
2021-03-25 16:01:26
@JGallardo 我稍微重写了这个例子,所以它添加了sup标签(或任何其他标签),它包含在一个函数中:jsfiddle.net/E3EqX/4要使用它,您需要将“encodeAndWrap”函数复制到您的项目中。
2021-04-02 16:01:26
@SB 谢谢你的说明,我什至要投最后的赞成票 :)
2021-04-02 16:01:26
非常感谢您的 jsfiddle。所以要实现这一点。我可以将它添加到我的.js文件中并添加其他内容以用<sup>?
2021-04-04 16:01:26

当前接受的答案有几个问题。这篇文章解释了它们,并提供了一个更强大的解决方案。该答案中建议的解决方案以前有:

var encodedStr = rawStr.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
  return '&#' + i.charCodeAt(0) + ';';
});

i标志是多余的,因为从 U+00A0 到 U+9999 范围内的任何 Unicode 符号都没有超出同一范围的大写/小写变体。

m标志是多余的,因为^或未$在正则表达式中使用。

为什么范围是 U+00A0 到 U+9999?似乎是随意的。

无论如何,对于在输入中正确编码除安全和可打印 ASCII 符号之外的所有符号(包括星形符号!)并实现所有命名字符引用(不仅仅是 HTML4 中的那些)的解决方案,请使用he(免责声明:这个库是我的) )。从它的自述文件:

he(代表“HTML 实体”)是一个用 JavaScript 编写的强大的 HTML 实体编码器/解码器。它支持所有标准化的 HTML 命名字符引用像浏览器一样处理不明确的&符号和其他边缘情况,具有广泛的测试套件,并且——与许多其他 JavaScript 解决方案相反——可以很好地处理星体 Unicode 符号。提供在线演示。

另请参阅此相关堆栈溢出答案

@drzaus 图像可以避免变大,因为它们存储了大量数据,压缩数据越少解码速度越快。然而程序代码是不同的,经常添加整个库并且很少使用它。库的代码有时比您自己的代码包含更多行!此外,很少有人会费心查找/调试库问题并发送错误报告(甚至更新库),因此内存泄漏或其他问题可能会在具有许多库和未经检查的代码的软件中持续存在。如果有人只想编码/转义 html-unsafe 字符,只需要几行,而不是 80kb。
2021-03-21 16:01:26
@FlorianMertens 在缩小 + gzip 之后,是 ~24 KB。这仍然很大,但归根结底,如果您想正确解码 HTML 实体,您将需要它们的所有数据 - 没有办法绕过它。如果你能找到一种在不影响性能的情况下使库变小的方法,请提交拉取请求。
2021-04-03 16:01:26
@MarcoKlein 是的,我在我的帖子中解释了这一点。这确实是有问题的代码片段所遭受的问题。我指出的解决方案没有这个问题。(参见“包括星体符号!”)
2021-04-04 16:01:26
此外,HE 库是... 84KB!Autch... 尝试通过较小的连接在移动电话上下载它。必须在某处做出妥协..
2021-04-05 16:01:26
@MathiasBynens,毫无疑问你的图书馆很好,但你可以使用评论框在已接受的答案中突出显示问题,请在代码块中提交改进的答案
2021-04-05 16:01:26

我遇到了同样的问题并创建了 2 个函数来创建实体并将它们转换回正常字符。以下方法将任何字符串转换为 HTML 实体并返回字符串原型

/**
 * Convert a string to HTML entities
 */
String.prototype.toHtmlEntities = function() {
    return this.replace(/./gm, function(s) {
        // return "&#" + s.charCodeAt(0) + ";";
        return (s.match(/[a-z0-9\s]+/i)) ? s : "&#" + s.charCodeAt(0) + ";";
    });
};

/**
 * Create string from HTML entities
 */
String.fromHtmlEntities = function(string) {
    return (string+"").replace(/&#\d+;/gm,function(s) {
        return String.fromCharCode(s.match(/\d+/gm)[0]);
    })
};

然后,您可以按如下方式使用它:

var str = "Test´†®¥¨©˙∫ø…ˆƒ∆÷∑™ƒ∆æø𣨠ƒ™en tést".toHtmlEntities();
console.log("Entities:", str);
console.log("String:", String.fromHtmlEntities(str));

控制台输出:

Entities: &#68;&#105;&#116;&#32;&#105;&#115;&#32;&#101;&#180;&#8224;&#174;&#165;&#168;&#169;&#729;&#8747;&#248;&#8230;&#710;&#402;&#8710;&#247;&#8721;&#8482;&#402;&#8710;&#230;&#248;&#960;&#163;&#168;&#160;&#402;&#8482;&#101;&#110;&#32;&#116;&#163;&#101;&#233;&#115;&#116;
String: Dit is e´†®¥¨©˙∫ø…ˆƒ∆÷∑™ƒ∆æø𣨠ƒ™en t£eést 
是不是有点极端?您正在将所有内容转换为 HTML 实体,甚至是“安全”字符,例如“abc”、“123”……甚至是空格
2021-03-23 16:01:26
此解决方案也适用于 tvOS,因此它可以很好地解决所有情况下的编码问题。
2021-03-30 16:01:26
请解释m模式修饰符在没有锚点模式中的用途所以你的意思是s用于包含点的模式?
2021-03-30 16:01:26
这是一个糟糕的答案。网络上 50% 以上的文档主要包含 latin1 和一些 utf-8。您对安全字符的编码会将其大小增加 500% 到 600%,但没有任何优势。
2021-04-01 16:01:26

这是人们在谷歌上搜索如何编码 html 实体的答案,因为它并没有真正解决关于 <sup> 包装器和符号实体的问题。

对于没有任何库的 HTML 标签实体(&、< 和 >),如果您不需要支持 IE < 9,您可以创建一个 html 元素并使用Node.textContent设置其内容

var str = "<this is not a tag>";
var p = document.createElement("p");
p.textContent = str;
var converted = p.innerHTML;

这是一个例子:https : //jsfiddle.net/1erdhehv/

为什么不使用innerText 而不是textContent?
2021-03-18 16:01:26
@Rick,试一试答案中链接的 textContent 的 MDN 文档。引用它“ textContent 和 HTMLElement.innerText 很容易混淆,但这两个属性在重要方面不同的。”
2021-03-20 16:01:26
这将是一个很好的解决方案,但它没有正确编码 " 字符。
2021-03-22 16:01:26
你说的对。看起来此解决方案可能仅适用于 html 标记字符(<、>、/)。我很想删除它。
2021-04-06 16:01:26

你可以用这个。

var escapeChars = {
  '¢' : 'cent',
  '£' : 'pound',
  '¥' : 'yen',
  '€': 'euro',
  '©' :'copy',
  '®' : 'reg',
  '<' : 'lt',
  '>' : 'gt',
  '"' : 'quot',
  '&' : 'amp',
  '\'' : '#39'
};

var regexString = '[';
for(var key in escapeChars) {
  regexString += key;
}
regexString += ']';

var regex = new RegExp( regexString, 'g');

function escapeHTML(str) {
  return str.replace(regex, function(m) {
    return '&' + escapeChars[m] + ';';
  });
};

https://github.com/epeli/underscore.string/blob/master/escapeHTML.js

var htmlEntities = {
    nbsp: ' ',
    cent: '¢',
    pound: '£',
    yen: '¥',
    euro: '€',
    copy: '©',
    reg: '®',
    lt: '<',
    gt: '>',
    quot: '"',
    amp: '&',
    apos: '\''
};

function unescapeHTML(str) {
    return str.replace(/\&([^;]+);/g, function (entity, entityCode) {
        var match;

        if (entityCode in htmlEntities) {
            return htmlEntities[entityCode];
            /*eslint no-cond-assign: 0*/
        } else if (match = entityCode.match(/^#x([\da-fA-F]+)$/)) {
            return String.fromCharCode(parseInt(match[1], 16));
            /*eslint no-cond-assign: 0*/
        } else if (match = entityCode.match(/^#(\d+)$/)) {
            return String.fromCharCode(~~match[1]);
        } else {
            return entity;
        }
    });
};
手动添加可编码字符的随机子集可能会给您和您的同事带来麻烦。应该有一个单一的权限来编码字符,可能是浏览器或可能是全面和维护的特定库。
2021-03-19 16:01:26
这会错过很多的HTML实体,如sunch&rdquo; &uuml; &scaron;等所有HTML实体的comprihensive名单很长:freeformatter.com/html-entities.html
2021-04-01 16:01:26
好点子,@ user234461。如果有人找到了这个单一的权威,有好奇心的人(像我一样)很想知道!
2021-04-02 16:01:26