跳到正文

← 全部工具

免费在线工具

HTML 实体编码解码与 Unicode 检查

把文本转成 HTML 实体或还原,看清一段文本由哪些码位、字节和字符组成,并得到 JavaScript、JSON、Python、CSS 字符串用的转义序列。不会上传任何内容,全部在本页里运行。

把文本转成 HTML 字符引用(&、é、😀),或把它们还原成文本。

方向
编码哪些字符

第一项是把文本安全放进 HTML 时用的。后两项用于只接受纯 ASCII 的系统。

写成

名字模式下撇号始终写成 ',因为 ' 不属于 HTML 4。

已编码 9 个字符:8 个用名字,1 个用数字。

它是怎么工作的

  • •HTML 实体:第一种模式只把 & < > " 和 ' 写成引用,这正是把文本放进 HTML 页面或带引号的属性时需要的。另外两种模式会把所有非 ASCII 字符或所有字符也写出来,给只接受纯 ASCII 的系统用。可以写成名字(&eacute;)、十进制(&#233;)或十六进制(&#xE9;)。表情符号写成一个引用,而不是两个半截。
  • •解码只做一遍,所以 &amp;lt; 变成 &lt;,而不是 <。它认十进制和十六进制引用,以及下一条说的 253 个命名引用。数字引用遵循 HTML 标准:&#0;、代理项和大于 U+10FFFF 的值变成 U+FFFD,&#128; 到 &#159; 按 Windows-1252 字符读取(&#150; 是短破折号)。这里的命名引用必须带结尾分号。不认识的内容原样保留,并列出来。
  • •名字表共 253 项:HTML 4.01 的 252 个名字(带音调的字母、希腊字母、箭头、常用符号、&nbsp;、&copy;、&euro; 等)加上 &apos;。Python 自带的 HTML5 表有 2,125 个名字,所以还有很多少见的名字本页不会解码。这张表是用脚本从 Python 的表生成的,不是手敲的。
  • •Unicode 检查:码位是 Unicode 表里的一个编号。JavaScript 按 UTF-16 单元计数,一个表情占两个;文件和网页多用 UTF-8,一个码位占一到四个字节。读者眼里的一个字符(字形簇)可能由多个码位组成,这个数字来自你浏览器的文本切分。类别(字母、组合符号、符号)来自浏览器自带的 Unicode 数据,所以很新的字符在较旧的浏览器里可能显示为未分配。这里不显示字符名称,因为名称表会让本页大很多。
  • •规范化:NFC、NFD、NFKC、NFKD 四种形式由你的浏览器生成。NFC 和 NFD 只在等价写法之间转换,比如 e 加组合音调与单个字母 é。NFKC 和 NFKD 还会替换外观相近的字符,比如 fi 连字,可能改变含义。
  • •转义格式:JavaScript 的 \uXXXX(表情变成代理项对)、JavaScript 的 \u{X}、JSON、Python(\xXX、\uXXXX、\UXXXXXXXX)和 CSS(\X,只有当下一个字符会被误读成数字的一部分时才在后面加空格)。反斜杠和控制字符总会被转义,字符串用哪种引号由你选。孤立代理项和 U+0000 无法写进 CSS,也无法写成 HTML 引用,会变成 U+FFFD 并提示你。
  • •怎么验证的:逻辑与 Python(html、unicodedata、json、ast)、Perl(字形簇)和 Node 自带的解析器在 156 个字符串上做了对比,其中有表情、组合符号、连接符序列、孤立代理项和形似实体的乱码;全部 1,114,112 个码位的字符类别也和 Python 的做了对比,只有一个码位不同(U+0295,在最新的 Unicode 数据里类别与 Python 的不一样)。有少数字符串没有参加部分对比,因为 Python 或 Perl 的 Unicode 数据或字形簇规则比你的浏览器旧(比如天城文的连字)。超过 200,000 个字符的文本会被拒绝并给出提示,而不是硬处理。

编码不等于消毒

哪些字符危险取决于文本放在哪里。在 HTML 文本和带引号的属性里,& < > 和引号是关键,第一种模式正好覆盖。在 <script> 或 <style> 块里,实体根本不会被解码,需要用 JavaScript 或 CSS 的转义。在 href 这样的链接里,编码拦不住 javascript: 地址,必须检查协议。在不带引号的属性里,空格和许多其他字符都会出问题。

本页只改变文本,不会删除标签、检查网址,也不知道你要把结果贴到哪里。它不是消毒工具,不能让不可信的输入变安全。请使用模板引擎针对对应场景的内置转义;也不要先用“解码”处理不可信文本,再把结果当作 HTML 放进页面。

常见问题

会上传我的文本吗?
不会。所有计算都由本页里运行的代码完成,不会发送到任何地方。复制也在你的设备上完成。
为什么看起来一个字符,却算成好几个?
文本是按码位存储的。字母 é 可以是一个码位(U+00E9,UTF-8 占 2 字节),也可以是 e 加一个组合音调(2 个码位,3 字节)。由三个人用不可见连接符连起来的家庭表情是 5 个码位、8 个 UTF-16 单元、18 个 UTF-8 字节,但读者只看到一个字符。检查页里的第一个示例就能看到。规范化成 NFC 会把 e 和音调合成一个字母。
为什么 &bigstar; 没有被解码?
因为它不在本页的 253 个名字表里。与其乱猜,不如保持原文并列出来。HTML5 有两千多个名字,本页只认常见的。数字引用比如 &#9733; 永远可用。
用第一种模式,我的页面就能防住跨站脚本攻击吗?
只有当文本放进 HTML 文本或带引号的属性时才算。对 script 块、style 块、网址和不带引号的属性都没有作用,也不能代替你所用框架的转义。见上面的说明。

相关工具