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 Jackson | ESCAPE_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 粘进去:
- 默认关闭「转义非 ASCII」:格式化 / 压缩后,中文会以可读字面量显示(
北京),因为内部先parse再stringify,等价于一次无损往返; - 若你需要故意输出
\uXXXX(给只认 ASCII 的下游),勾选「转义非 ASCII」再点格式化或压缩即可; - 全程在浏览器本地解析,数据不会上传到任何服务器。
提示:
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)、存储(库表字符集)、消费者解码。垃圾形态往往能指认是哪一层:
| 形态 | 更可能的原因 |
|---|---|
??? | 有损转换已经发生,数据在上游被弄丢 |
䏿–‡ 一类 mojibake | UTF-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 编解码。访问 首页 查看更多开发者工具。
相关工具
相关文章
JSON 大整数精度陷阱:雪花 ID 被静默改写时怎么查
超过 2^53-1 的 JSON 数字经 JSON.parse 会尾部舍入。对照劣质格式化与无损路径,并互链 JWT/Base64 与站内 JSON 工具。
JSON 解析报错 Unexpected token?5 种常见原因和修复方法
JSON 解析报错 Unexpected token?本文总结 5 种最常见的 json 格式错误原因:尾逗号、单引号、未转义字符、BOM 头、注释,逐一给出修复方法和代码示例。
JSON 排错完全手册:从报错信息到修复(按症状速查)
JSON 报错看不懂?本手册按「症状 → 原因 → 修复」组织,覆盖语法错误、中文转义、编码乱码、Schema 校验失败四类高频问题,附诊断决策树与通用排查流程。