宝塔拨测博客拨测技术博客
宝塔拨测

中文转 Unicode 得到 中 不是 \u4e2d:三种写法的区别与页面显示成串码的原因

宝塔的文本 / Unicode 互转工具页面上写着「文本 → Unicode 按字符 charCode 转为 &#数字; 形式实体」。也就是说,它出的是 HTML 的十进制字符引用,不是很多人以为的 \u4e2d 那种十六进制转义。实测输入「中文」,结果框是 中文。

这两种写法表示的是同一个字符,但用在不同的地方,混着用就会卡住:把 \u4e2d\u6587 粘进它的反解框,直接报「未识别到合法的 Unicode 实体(形如 A)」。

下面每个输入输出都来自 2026-11-09 11:36 前后的同一次运行,截图与正文数字同源,转换在浏览器本地完成、不上传服务器。

同一个字,几种写法

「中」这个字符有多个身份,先分清再用工具,后面大部分坑都从这里来:

形式 写法 用在哪 本质
字符本体 中 HTML 正文、源码、数据库 一个 Unicode 字符
十进制实体 中 HTML / XML 正文 码点 20013 的十进制
十六进制实体 中 HTML / XML 正文 码点 0x4E2D
十六进制转义 \u4e2d JavaScript 字符串、JSON、CSS 的 \4e2d 码点 0x4E2D
百分号编码 %E4%B8%AD URL、表单 UTF-8 三个字节,不是码点

关键区别在于「码点」和「字节」:除最后一行外,前几行说的都是码点 U+4E2D 的不同记法,只是进制和包装语法不同;最后一行 %E4%B8%AD 是 UTF-8 编码后的字节序列,跟码点不是一回事(「中」在 UTF-8 下占 3 个字节,所以是 9 个字符)。

U+4E2D 的十进制是 20013,所以 中 和 中 指的是同一个字符。浏览器两种都认,但这个工具只认十进制那一半。

实测:中文转出来是 中文

在「文本转 Unicode」标签页输入「中文」,结果框立刻出现:

中文

两个字符换两个实体,每个实体一个分号结尾,中间没有空格。再看一个混排的例子,输入 BT 中文 ✅,输出是:

BT 中文 ✅

可以对照出来:B 是 B、T 是 T、空格是  、✅(U+2705)是 ✅。这个工具不分字符类型,ASCII 字母、空格、中文、emoji 全部换成实体,这一点和 HTML 实体工具只编 5 个字符的设计正好相反。

文本转 Unicode 标签页输入「中文」,结果框输出十进制实体

顺带说清一处:输出里的 & 没有被二次转义,结果就是 中 这几个字符,不是 中。工具只做一件事——把每个码元换成「& + # + 十进制数字 + 分号」。

反解只认 &#数字;:\u4e2d 和 中 都会报错

切到「Unicode 转文本」,输入 中文,输出是「中文」,一切正常。

换成 JavaScript 和 JSON 里常见的形式 \u4e2d\u6587,输出框是空的,下面出现红字:

未识别到合法的 Unicode 实体(形如 A)

换成十六进制实体 中文,报的还是同一句。

Unicode 转文本标签页输入反斜杠 u 转义形式,输出为空并提示未识别到合法的 Unicode 实体

这解释了一个很常见的困惑:从 JSON 接口里拿到 \u4e2d 形式的中文,或者从别人给的 HTML 源码里拿到 中,粘到这个工具都还原不了。不是格式坏了,是它的匹配规则只写了十进制那一种——页面说明也写明「Unicode → 文本按正则匹配 &#数字; 实体并还原为字符」。

要读接口返回的 \uXXXX,用 JSON 在线解析与格式化工具 里的「Unicode 转中文」;要处理命名实体和十六进制实体,用 HTML 实体编码工具。三个工具的适用边界不一样,粘错地方就会得出「工具坏了」的结论。

分号也不能省。实测输入 &#20013(少了结尾分号),同样报「未识别到合法的 Unicode 实体(形如 A)」,输出为空。

文本中间的实体可以混着解。输入 A 中 B,输出是 A 中 B:实体段被替换,前后的普通字符原样保留,空格也照旧。

Unicode 转文本标签页输入十进制实体,结果框输出中文

emoji 转出来是两个代理码元,贴进网页会变乱码

这是这个工具最需要注意的一处。输入 中文😀,输出是:

中文��

😀 的码点是 U+1F600,十进制 128512。但工具取的是 UTF-16 码元,不是码点:一个 16 位码元装不下 128512,这个字符在 UTF-16 里被拆成 0xD83D 和 0xDE00 两个码元,换算成十进制就是 55357 和 56832。

按 HTML 规范,字符引用里出现代理码点属于解析错误,浏览器会把每个代理码元换成 U+FFFD 替换字符。实测把这串输出原样放进页面,渲染结果如下:

页面里写的 实际渲染 渲染出的码点
中文�� 中文�� U+4E2D U+6587 U+FFFD U+FFFD
😀 😀 U+1F600

同一段文字,正确写法是 😀 一个实体,工具给的是两个代理码元,贴到网页上就成了两个乱码字符。

文本转 Unicode 标签页输入中文加笑脸 emoji,结果框输出两个代理码元实体

有意思的是,把这串 �� 粘回它的反解框,输出就是 😀:码点 U+1F600,码元 0xD83D 与 0xDE00,两个代理码元拼回了一个字符。反解用的是逐码元 fromCharCode,所以工具自己往返是对的,换到浏览器解析就不对了——这类「工具内部自洽、出圈就错」的结果,只有真的把输出贴进页面才会发现。

反方向也有一个要留意的:如果手上拿到的是正确写法 😀,粘进这个工具的反解框,得到的字符码点是 U+F600,不是 U+1F600。超出 U+FFFF 的值被截断了。所以还原 emoji 这类字符,别指望一次粘贴,要看输出的码点核对,不能只看字形。

网页上显示 中 是怎么回事

标题里这个问题,通常不是编码出了错,而是这串字符根本没被当成 HTML 字符引用解析。按出现位置分两类:

第一类:值被写进了不解析实体的地方。

  • 用 textContent / innerText 赋值,值按原样写入,中 就是几个可见字符;
  • 用 setAttribute 设置属性值,同理;
  • 放在 script、style 里,这两个元素内的文本不做字符引用替换;
  • 在 JSON 响应里,实体串只是一个普通字符串,前端取出来直接显示就带着 &#。

第二类:被编码了两次。 页面源码里出现 中 时,浏览器解一层得到 中,再显示成字面串。这种情况要把源头那一次多余的转义去掉,而不是继续在页面上加解码。

还有一个容易混的现象:如果整页中文都成了乱码(比如「涓枃」这种),那不是实体问题,是字符集声明和实际字节不一致,跟 中 无关,别往这个工具上找原因。

什么时候该用哪种写法

页面本身是 UTF-8 时,正文直接写中文最稳,不需要任何转义。真正需要转的场景是「通道只允许 ASCII」:

  • HTML / XML 正文:用 中 或 中 都行,浏览器按规范解析。宝塔这个工具给的就是十进制形式,可以直接用;
  • JavaScript 字符串、JSON:用 \u4e2d 或直接写 UTF-8 中文;中 在 JSON 字符串里不会被解析,只会原样显示;
  • CSS:用 \4e2d 形式(反斜杠加十六进制,必要时后面跟一个空格隔开),CSS 里没有 &# 这种用法;
  • URL 参数:用 %E4%B8%AD,这是 UTF-8 字节的百分号编码,不是码点,别把 中 塞进 URL;
  • 邮件主题、短信、只吃 ASCII 的老系统:用十进制实体 中,这类通道对 \u 转义通常不认。

反过来判断也简单:输入框里是 &# 开头,用这个工具;是 \u 开头,用 JSON 工具;是 < & © 这类带名字的,用 HTML 实体工具。

这个工具适合什么

按实测行为,它适合三件事:把中文或任意文本转成十进制 HTML 实体,用于只接受 ASCII 的通道;把从网页源码里抠出来的 &#数字; 串还原成可读文字;核对某个字符码点的十进制值(中 去掉前缀和分号就是 20013)。

它不适合两件事:还原 \uXXXX 转义(会报错),以及处理 emoji 这类超出 U+FFFF 的字符(编码输出代理码元、解码会截断)。这两类去用对应的工具,别在这里反复试。

常见问题

中文转 Unicode 为什么得到 中 而不是 \u4e2d?

因为这两种写法属于两套不同的标记语言。中 是 HTML 的十进制字符引用,后面的数字 20013 就是「中」的码点;\u4e2d 是 JavaScript 与 JSON 的十六进制转义,同一个码点写作 0x4E2D。宝塔这个工具只做前者,页面说明写的就是「文本 → Unicode 按字符 charCode 转为 &#数字; 形式实体」,实测输入「中文」输出 中文。

把 \u4e2d\u6587 粘进「Unicode 转文本」为什么报错?

因为这个工具的反向只匹配 &#数字; 这一种形式。实测输入 \u4e2d\u6587,输出框为空,提示「未识别到合法的 Unicode 实体(形如 A)」;输入十六进制实体 中文 也报同一句。它不认反斜杠转义,也不认 &#x 前缀。

中 和 中 有什么区别?

同一个码点的两种写法:中 是十进制,后面的数字是 20013;中 是十六进制,x 表示后面按 16 进制读,4E2D 等于十进制的 20013。浏览器两种都认,但宝塔这个工具只认十进制,粘十六进制会报「未识别到合法的 Unicode 实体」。

为什么 emoji 转出来是 �� 而不是 😀?

工具按 UTF-16 码元逐个取值,不按码点。😀 的码点是 U+1F600,十进制 128512,超出单个 16 位码元能表示的范围,在 UTF-16 里拆成两个码元 0xD83D 和 0xDE00,十进制就是 55357 和 56832。正确写法应该是 😀 一个实体,而不是两个代理码元。

工具转出来的 emoji 实体贴到网页上为什么变成两个替换字符?

因为 � 这类值落在代理码点区间,HTML 解析时属于解析错误,规范要求换成 U+FFFD 替换字符(不同字体下显示为问号、方框或黑菱形)。实测把 中文�� 放进页面,渲染出来是「中文」加两个 U+FFFD;同一页面里写 😀 则正常渲染成 😀。工具自己粘回去能还原,是因为它的反向用 fromCharCode 逐码元拼回,恰好凑成代理对。

网页上直接显示 中 这一串,是什么原因?

说明这串字符没有被当成 HTML 字符引用解析。两种常见情况:一是它被写进了 textContent、value 或 setAttribute,这些接口按原样赋值;二是它在 script、style 这类不解析字符引用的元素里。另外,内容被编码两次时会显示成 中,那是另一个问题。

什么时候真的需要把中文转成实体?

页面本身是 UTF-8 时不需要,直接写中文最省事。需要转的场景是通道只允许 ASCII:邮件主题、部分短信网关、只接受 ASCII 的老系统表单。这时优先用 中 这种十进制实体,别用 \u 转义——后者只有 JavaScript 字符串和 JSON 里才有意义,写进 HTML 正文会原样显示成 \u4e2d。

Unicode 转中文中文转 Unicode字符实体码点Unicode 转义宝塔拨测