\uXXXX 是码元不是码点
JSON 的 \u 转义后固定跟 4 位十六进制,它表示的是一个 UTF-16 码元,而不是一个 Unicode 码点。基本多文种平面(U+0000 到 U+FFFF)里两者一一对应;超出该平面的字符必须拆成高位代理加低位代理两个 \u 转义。理解这一点,才能解释为什么同一个 emoji 会写成两段转义。
基本信息
| 写法 | \uXXXX,X 为十六进制数字,大小写均可,务必补齐 4 位 |
|---|---|
| 高位代理 | U+D800 到 U+DBFF |
| 低位代理 | U+DC00 到 U+DFFF |
| 码点换算 | 码点 = 0x10000 + (高位 - 0xD800) × 0x400 + (低位 - 0xDC00) |
| 是否必需 | 不必须。JSON 允许 UTF-8 原文字符,\u 转义主要用于 ASCII 安全通道 |
典型使用场景
- 接口要求纯 ASCII 请求体,中文与 emoji 必须转义后传输
- 把 JSON 嵌进 HTML 脚本或 HTTP 头,避免非 ASCII 字节被中间层改写
- 排查前端显示乱码:确认代理对是否被截断成单个 \u 转义
- 生成测试数据:用转义形式精确控制字符,避免编辑器插入不可见字符
- 跨语言对拍:Python、Java、JS 对同一字符串的转义输出应一致
生成与还原
生成与还原
# 生成:非 ASCII 全部转义(非 BMP 自动写成代理对)
json.dumps('中文😀', ensure_ascii=True) # '\u4e2d\u6587\ud83d\ude00'
# 还原:解析器自动合并代理对
json.loads('"\\ud83d\\ude00"') # '😀'
# 手工换算码点(验证转义是否正确)
cp = 0x10000 + (0xD83D - 0xD800) * 0x400 + (0xDE00 - 0xDC00)
hex(cp) # 0x1f600
chr(cp) # 😀常见字符的两种写法
| 字符 | 原文字符 | \u 转义 |
|---|---|---|
| 中 | 中 | \u4e2d |
| A | A | \u0041(可省) |
| 换行 | \n | \u000a(可用 \n) |
| 笑脸 | 😀 | \ud83d\ude00 |
| 不换行空格 | U+00A0 | \u00a0 |
JSON 语法允许出现孤立代理(不成对的高位或低位),但 RFC 8259 明确指出收到这类文本的软件行为不可预测。遇到半个代理对应当判定为脏数据,而不是当成正常字符继续处理。
转义只改变表示,不改变语义:\u4e2d 与原文字符「中」在解析后完全等价。因此字符串比较、长度统计应在解析后进行,比较原始文本里有没有转义是没意义的。