跳到主要内容
JSON 工具2026-08-285 分钟阅读

JSON 格式化后中文变成 \uXXXX 转义,怎么还原成中文?

现象:中文被转成了 \uXXXX

你把一个含中文的 JSON 粘进格式化工具,结果输出里的中文变成了这样:

{
  "name": "\u4e2d\u6587",
  "city": "\u5317\u4eac"
}

明明想看的是 "北京",却变成了一串 \uXXXX 形式的字符。很多人第一反应以为是"乱码"或"工具坏了"。其实不是——这是 JSON 完全合法的 Unicode 转义,而且数据并没有损坏。

反过来也常见:日志里全是 \uXXXX,你想对照接口文档里的「可读中文」样例,肉眼比对几乎不可能。弄清「谁在转义、谁在还原」,比到处改编码声明省事得多。

为什么会出现这种转义

JSON 字符串规范允许用 \uXXXX 来表示任意 Unicode 字符(XXXX 是 4 位十六进制码点)。问题出在生成 JSON 的一方默认开启了 "ASCII-only" 输出:

语言 / 库默认行为是否转义中文
Python json.dumps()ensure_ascii=True(默认)✅ 转义成 \uXXXX
Java JacksonESCAPE_NON_ASCII(常见默认)✅ 转义
PHP json_encode(未加 JSON_UNESCAPED_UNICODE)转义✅ 转义
JavaScript JSON.stringify()不转义❌ 保留中文
Go encoding/json不转义❌ 保留中文

所以你看到的 \u5317\u4eac 就是 "北京" 的 UTF-16 码点表示,只是显示形式不同,含义完全一样。

RFC 8259 允许字符串里直接放 UTF-8 字面量——{"name":"李帅"} 在现代解析器里都合法。许多序列化器仍默认 \uXXXX,多半是历史包袱(早期传输通道会糟蹋 8 位字节)和「消费者解码更保守」的习惯。今天更常见的做法:默认输出 UTF-8 字面量(diff 可读、CJK 大约 3 字节 vs 转义 6 字符),只按规范转义引号、反斜杠和控制字符。

怎么还原成中文

方法一:用在线工具一键还原

打开 ToolVault 工具匣 的 JSON 格式化工具,把这段 JSON 粘进去:

  1. 默认关闭「转义非 ASCII」:格式化 / 压缩后,中文会以可读字面量显示(北京),因为内部先 parse 再 stringify,等价于一次无损往返;
  2. 若你需要故意输出 \uXXXX(给只认 ASCII 的下游),勾选「转义非 ASCII」再点格式化或压缩即可;
  3. 全程在浏览器本地解析,数据不会上传到任何服务器。

提示:JSON.parse() 本身就会自动把转义还原成字符。真正麻烦的是生成端默认转义,而展示端如实显示了原始内容。单段字符串(不是完整 JSON)也可以用 Unicode 编解码 查看码点与 \uXXXX 对照。

方法二:从代码层面避免转义

如果你是自己生成 JSON,把 ASCII-only 关掉就行:

import json
data = {"name": "中文", "city": "北京"}
# 默认会转义成 \uXXXX
print(json.dumps(data))
# 关闭转义,保留中文
print(json.dumps(data, ensure_ascii=False))
const data = { name: '中文', city: '北京' };
// JSON.stringify 默认就保留中文,不会转义
console.log(JSON.stringify(data));
// Jackson:关闭非 ASCII 转义
ObjectMapper mapper = new ObjectMapper();
mapper.configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, false);
String json = mapper.writeValueAsString(data);
// PHP 7+:保留 Unicode 字面量
echo json_encode($data, JSON_UNESCAPED_UNICODE);

什么时候该保留转义

并不是所有场景都要还原。以下情况保留 \uXXXX 反而更稳妥:

  • 日志 / 配置文件要兼容只认 ASCII 的老系统;
  • 跨语言传输时,对方解析器对 UTF-8 支持不好;
  • 避免 BOM / 编码声明不一致导致的二次乱码。

一句话:人要看 → 还原成中文;机器要稳 → 保留转义。 同一条链路里不要混用两种表示——边界上选一种,并用金丝雀字符串(如 李帅✓)做往返校验。

代理对陷阱:生僻字与 emoji

BMP 里常见汉字(大约两万个)一个 \uXXXX 就够。BMP 之外——大量 emoji、部分生僻汉字——需要代理对:\ud840\udc00,两个转义拼成一个字符。经典坑:手写转义解码按「一次四个十六进制」拆,结果拆出两个乱码;length 按 UTF-16 单位算会得到 2,人眼却只看到 1(截断「最多 20 字」时容易切坏)。现代引擎(JS 字符串迭代、Python 3)按码点处理;危险区是自写转义器和按 length 截断的代码。测转义逻辑时,别只拿「中文」当样例,再加一个 emoji 或 astral 汉字。

编码链路五层排查

管道里的「中文坏了」通常经过五层:源文件编码、序列化开关、传输(HTTP charset)、存储(库表字符集)、消费者解码。垃圾形态往往能指认是哪一层:

形态更可能的原因
???有损转换已经发生,数据在上游被弄丢
中文 一类 mojibakeUTF-8 字节被按 Latin-1/GBK 误解码,多数可逆
输出里仍可见 \uXXXX双写转义,或展示层没做 parse

从源端往消费端逐层改,改不动就先命名「卡在哪一层」——随机换编码声明只会把一处损坏变成两处。

FAQ

\uXXXX 是乱码吗?

不是。它是 Unicode 码点的标准转义写法,任意 JSON 解析器都能无损还原。真正的乱码通常是 GBK/UTF-8 编码错配导致的 中文 这种看不懂的字符。

为什么我的 JSON 在浏览器里能显示中文,粘到工具里就变转义了?

很可能是复制的来源(后端接口、日志)本身就是 ASCII-only 输出。工具若「如实显示原文」就会看到转义;用 JSON 格式化 默认模式(关闭「转义非 ASCII」)格式化一次,就会变成可读中文。

还原后会改变数据吗?

不会。转义和非转义是同一段数据的两种文本表示,解析后得到的字符串完全一致。可用本站 JSON Diff 对比「转义版」与「字面量版」:结构相同、仅字符串书写形式不同时,语义上仍是同一文档。

只想转义某一个字段怎么办?

完整 JSON 用格式化工具的全局开关;单个字符串用 Unicode 编解码。不要在业务代码里手写半截 \u 拼接——代理对和大小写十六进制很容易写错。

实现注记

用 JSON Diff 核对转义改动时不必担心数字失真:解析走无损模式保留大整数原文,同值大整数按原文相等处理,实例引用不等不算差异——数值相同的长 ID 被误报成 modified 的假阳性,上线前被专门修掉过。


本文出自 ToolVault 工具匣。更多 JSON 相关工具:JSON 格式化、JSON Diff、JSONPath 查询、JSON Schema 校验、Unicode 编解码。访问 首页 查看更多开发者工具。