字符编码入门:Unicode 是值,UTF 是编码,GBK 是另一套
一、两个不同层次的东西
处理文本时有两件独立的事,很多人会混:
第一层:字符编码方案 —— 决定"字符 ↔ 字节"怎么对应。
第二层:转义/包装手段 —— 当字节必须穿过只认 ASCII 的通道时,临时把字节包装成 ASCII 字符串。
二、第一层:字符编码方案
1. Unicode 与 UTF-8/16/32
Unicode 是编号表:每个字符一个编号(码点)。"中"= U+4E2D,"A"= U+0041。
UTF-8/16/32 是把编号写成字节的规则:
| 字符 | Unicode 编号 | UTF-8 字节 | UTF-16 字节 | UTF-32 字节 |
|---|---|---|---|---|
| 中 | U+4E2D | E4 B8 AD(3 字节) | 4E 2D(2 字节) | 00 00 4E 2D(4 字节) |
| A | U+0041 | 41(1 字节) | 00 41 | 00 00 00 41 |
- UTF-8:1–4 字节变长,兼容 ASCII,无字节序问题 → 互联网主流。
- UTF-16:1–2 个 16 位单元,有代理对、有大小端 → 内存/旧系统常见。
- UTF-32:固定 4 字节,简单但浪费。
优点:Unicode 一套编号覆盖全世界;UTF-8 兼容 ASCII。
缺点:UTF-16 麻烦;UTF-32 占空间。
2. ASCII
128 个字符(0–127),英文、数字、标点、控制符。字符集和编码合一,一字符一字节。 "A"=65。"中"没有。
和 Unicode 的关系:ASCII 是 Unicode 的子集,U+0000–U+007F 完全一致。纯 ASCII 文本天然是合法 UTF-8。
3. 区域性旧编码(和 UTF-8 同一层,是竞争对手)
这些既是字符表也是编码规则,绑在一起,一步到位给出字节:
| 编码 | 用途 | 例子 |
|---|---|---|
| GB2312 | 简体中文,6763 常用汉字 | "中" → D6 D0 |
| GBK | GB2312 扩展,2 万多汉字 | 同上 |
| GB18030 | 覆盖全部 Unicode,1/2/4 字节变长 | — |
| Big5 | 繁体中文 | — |
| Shift_JIS | 日文 | "あ" → 82 A0 |
| ISO-8859-1 | 西欧 | "é" → E9 |
优点:当年各自解决本地语言,省空间(中文 2 字节)。
缺点:互不兼容,同一串字节在不同编码下意思不同 → 乱码。
和 Unicode 的关键区别:
- Unicode 分两步:字符 → 编号 → 字节。
- GBK 等一步到位:字符 → 字节,没有中间编号层。
- 所以 GBK 不是"Unicode 的某种编码",它是独立规范,和 UTF-8 平级。
三、第二层:转义/包装手段
它们不是字符编码方案,是"把字节或码点包装成 ASCII 字符串"的临时手段,收到后要解码还原。
为什么需要:有些通道只认 ASCII(URL、邮件头、源码文件),非 ASCII 字节过不去。
例子(都以"中"为例,底层用 UTF-8):
| 手段 | 写法 | 说明 |
|---|---|---|
| Unicode 转义 | \u4E2D | 直接写码点,源码里用 |
| HTML 实体 | 中 或 中 | 网页里用,浏览器解码 |
| URL 编码 | %E4%B8%AD | 把 UTF-8 字节 E4 B8 AD 每个字节写成 %XX |
| Base64 | 5Lit | 把字节 E4 B8 AD 重新映射到 64 个安全字符 |
优点:让非 ASCII 内容安全穿过 ASCII 通道。
缺点:变长、不可读、需要解码。
关键:包装手段和底层编码独立。GBK 也能被 URL 编码:%D6%D0。
类比:UTF-8/GBK 是"语言本身",URL 编码/Base64 是"运输包装"。
四、串成一条线
字符"中"
├─ GBK(一步到位):→ 字节 D6 D0
└─ Unicode(两步):
查编号 → U+4E2D
├─ UTF-8 → 字节 E4 B8 AD
│ ├─ URL 编码 → %E4%B8%AD
│ └─ Base64 → 5Lit
├─ UTF-16 → 字节 4E 2D
└─ 转义序列 \u4E2D(直接写编号)