同一个字符,六种写法
不同语言和格式各有自己的 Unicode 转义语法,容易混淆的根本原因是它们转义的「单位」不同:有的是 UTF-16 码元,有的是 Unicode 码点,有的是编码后的字节。跨系统传递一段文本时,必须确认当前这层写的是哪一种单位,否则会出现半个代理对、多余零位或被截断的字符。
基本信息
| HTML/XML 数字实体 | 中 十六进制或 中 十进制,单位是码点,分号必需 |
|---|---|
| JSON / Java | \uXXXX,单位是 UTF-16 码元,非 BMP 要写代理对 |
| JavaScript 字面量 | \uXXXX 或 ES6 起的 \u{1F600},后者单位是码点 |
| Python | \uXXXX、\U0001F600、\N{GENERIC CHARACTER NAME} |
| CSS | \4E2D,1 到 6 位十六进制,单位是码点,可省略前导零 |
| URI / 表单 | %E4%B8%AD,单位是字节,按 UTF-8 编码后再做百分号编码 |
典型使用场景
- 接口联调:确认对方发的 \uXXXX 是否需要自己再合并代理对
- 写配置文件或模板,避免编辑器把不可见字符吃掉
- 排查 URL 乱码:百分号编码解出的字节流要用正确字符集还原
- Java 项目里写正则或路径,注意 \u 在编译前期就被替换
- 脚本里输出控制字符,bash 的 $'\u4e2d' 与 printf 是两种做法
同一字符「中」的多种写法
同一字符「中」的多种写法
HTML/XML : 中 或 中 # 码点,分号必需
JSON : "\u4e2d" # UTF-16 码元
Java : "\u4e2d" # 同 JSON,全文件预扫描
Python : "\u4e2d" / "\N{CJK ...}" # 码点,\U 用于 BMP 以上
CSS : .x::before{content:"\4E2D"} # 码点,可省前导零
JS : "\u4e2d" / "\u{4e2d}" # ES6 起支持花括号形式
URI : %E4%B8%AD # UTF-8 字节,非码点表示法单位速查
| 表示法 | 单位 | 非 BMP 示例 |
|---|---|---|
| \uXXXX(JSON/Java/JS) | UTF-16 码元 | \uD83D\uDE00 |
| \u{...}(JS 花括号形式) | 码点 | \u{1F600} |
| \UXXXXXXXX(Python/C) | 码点 | \U0001F600 |
| &#x...;(HTML/XML) | 码点 | 😀 |
| \1F600(CSS) | 码点 | \1F600 |
| %XX(URI) | UTF-8 字节 | %F0%9F%98%80 |
Java 源文件里的 \uXXXX 在词法分析之前就被替换,连注释里也会被处理,因此写路径或正则时要格外小心:\u000A 会在编译前变成真正的换行,把这一行拆断。
百分号编码是字节层表示,还原必须两步:先做百分号解码得到字节序列,再按声明或约定的字符集解码成文本。只做第一步会得到看起来像乱码的字节,只做第二步则连编码边界都找不到。