# 字符编码
# 一、国际标准编码体系
# ASCII
# 历史背景
- 由电报码发展而来,定义 128 个字符(33 控制字符 + 95 可显示字符)
- IANA (opens new window) 官方名称 US-ASCII
# 编码结构
控制字符(0-31、127)
- 详细对照表(二进制/十进制/十六进制/Unicode 表示)
- 典型应用:文本格式控制(换行、回车等)
可显示字符(32-126)
# 控制字符
ASCII 控制字符的编号范围是 0-31 和 127,共 33 个字符。
为方便人类用户阅读,各个控制字符均有 Unicode 表示法和脱出字符表示法:
| 二进制 | 十进制 | 十六进制 | 缩写 | Unicode 表示法 | 脱出字符表示法 | 名称 |
|---|---|---|---|---|---|---|
| 0000 0000 | 0 | 00 | NUL | ␀ | ^@ | 空字符 |
| 0000 0001 | 1 | 01 | SOH | ␁ | ^A | 标题开始 |
| 0000 0010 | 2 | 02 | STX | ␂ | ^B | 本文开始 |
| 0000 0011 | 3 | 03 | ETX | ␃ | ^C | 本文结束 |
| 0000 0100 | 4 | 04 | EOT | ␄ | ^D | 传输结束 |
| 0000 0101 | 5 | 05 | ENQ | ␅ | ^E | 请求 |
| 0000 0110 | 6 | 06 | ACK | ␆ | ^F | 确认回应 |
| 0000 0111 | 7 | 07 | BEL | ␇ | ^G | 响铃 |
| 0000 1000 | 8 | 08 | BS | ␈ | ^H | 退格 |
| 0000 1001 | 9 | 09 | HT | ␉ | ^I | 水平定位符号 |
| 0000 1010 | 10 | 0A | LF | ␊ | ^J | 换行键 |
| 0000 1011 | 11 | 0B | VT | ␋ | ^K | 垂直定位符号 |
| 0000 1100 | 12 | 0C | FF | ␌ | ^L | 换页键 |
| 0000 1101 | 13 | 0D | CR | ␍ | ^M | 回车键 |
| 0000 1110 | 14 | 0E | SO | ␎ | ^N | 取消变换 |
| 0000 1111 | 15 | 0F | SI | ␏ | ^O | 启用变换 |
| 0001 0000 | 16 | 10 | DLE | ␐ | ^P | 跳出数据通讯 |
| 0001 0001 | 17 | 11 | DC1 | ␑ | ^Q | 设备控制一 |
| 0001 0010 | 18 | 12 | DC2 | ␒ | ^R | 设备控制二 |
| 0001 0011 | 19 | 13 | DC3 | ␓ | ^S | 设备控制三 |
| 0001 0100 | 20 | 14 | DC4 | ␔ | ^T | 设备控制四 |
| 0001 0101 | 21 | 15 | NAK | ␕ | ^U | 确认失败回应 |
| 0001 0110 | 22 | 16 | SYN | ␖ | ^V | 同步用暂停 |
| 0001 0111 | 23 | 17 | ETB | ␗ | ^W | 区块传输结束 |
| 0001 1000 | 24 | 18 | CAN | ␘ | ^X | 取消 |
| 0001 1001 | 25 | 19 | EM | ␙ | ^Y | 连线介质中断 |
| 0001 1010 | 26 | 1A | SUB | ␚ | ^Z | 替换 |
| 0001 1011 | 27 | 1B | ESC | ␛ | ^[ | 退出键 |
| 0001 1100 | 28 | 1C | FS | ␜ | ^\ | 文件分割符 |
| 0001 1101 | 29 | 1D | GS | ␝ | ^] | 组群分隔符 |
| 0001 1110 | 30 | 1E | RS | ␞ | ^^ | 记录分隔符 |
| 0001 1111 | 31 | 1F | US | ␟ | ^_ | 单元分隔符 |
| 0111 1111 | 127 | 7F | DEL | ␡ | ^? | 删除键 |
# ISO 8859 系列
# ISO 8859-1
ISO 8859-1 是国际标准化组织内 ISO/IEC 8859 的第一个 8 位字符集。
- ASCII 扩展(0xA0 - 0xFF 新增 96 字符)
- 拉丁语系支持
- 与 Windows-1252 的区别:
- 码位 128 - 159 的字符差异
- 浏览器兼容处理机制
# 与 Unicode 关系
- 对应 Unicode 前 256 码位
- 多语言扩展的实现限制
# 与 Windows-1252 区别
Windows 为了支持英语和西欧字符,设计了一个编码,对应的代码页是 1252,因此被称为 Windows-1252。
Windows-1252 的设计,参考了 ANSI 草案,而 ANSI 草案后来发展成为正式的国际标准:ISO 8859-1。
ISO-8859-1 与 Windows-1252 代码页的区别是:
- 码位 128 - 159(0x80 - 0x9F)原本是罕用的 C1 控制字符编码范围,被替换为额外的一些常用但未包含在 ISO-8859-1 中的字符。
将 Windows-1252 文本误标为 ISO-8859-1,最常见的后果是所有引号和撇号[^1]在非 Windows 操作系统都变成问号或方格。
为了解决此问题,现在大部分网页浏览器和电邮用户端都将 MIME 字元集 ISO-8859-1 视作 Windows-1252 处理。
这也是 HTML5 标准要求的处理方式,要求将自称是 ISO-8859-1 的文件视作 Windows-1252 编码。
# Unicode 体系
Unicode 是一种信息技术标准,用于对世界上大多数书写系统中表达的文本进行一致的编码、表示和处理。
# 核心特性
- 统一字符集(U + 十六进制表示法)
- 基本多文种平面(BMP)与辅助平面
- 私用区应用实例(如苹果图标 U+F8FF)
Unicode 为每一个字符定义唯一的代码,同时,其首 256 个字符保留给 ISO 8859-1 所定义的字符,使既有的西欧语系文字的转换不需特别考量。
在表示一个 Unicode 的字符时,通常会用 U+ 然后紧接着一组十六进制的数字来表示这一个字符。
在基本多文种平面 (opens new window)里的所有字符,要用四个数字,即 2 字节,共支持六万多个字符;在零号平面以外的字符则需要使用五或六个数字。
# 字符平面映射
Unicode 将编码空间分成 17 个平面,以 0 到 16 编号。
基本多文种平面,即第 0 平面中的码点,都可以用一个 UTF-16 单位来编码,或者以 UTF-8 来编码的话,会使用一、二或三个字节。
而第 1 到 16 平面中的码点,UTF-16 会以代理对的方式来使用,而 UTF-8 则会编码成 4 个字节。
# 私用区
私人使用区位于零号平面 U+E000 至 U+F8FF,15 号平面 U+F0000 至 U+FFFFF 和 16 号平面 U+100000 至 U+10FFFF。
例如,苹果公司图标是 U+F8FF,即,当你用苹果提供的字体时,就能看到了。
# 编码实现
UTF-8 使用一至四个字节为每个字符编码:
- 128 个 US-ASCII 字符只需一个字节编码
- 带有附加符号的拉丁文、希腊文、西里尔字母、亚美尼亚语、希伯来文、阿拉伯文、叙利亚文及它拿字母则需要两个字节编码
- 其他基本多文种平面中的字符使用三个字节编码
- 其他极少使用的 Unicode 辅助平面的字符使用四个字节编码
UTF-16 编码机制:
- 代理对实现原理
- 平面映射关系
# 二、中文编码标准
# GB 系列
# GB2312(1980)
GB/T 2312-1980 是中华人民共和国国家标准简体中文字符集,全称《信息交换用汉字编码字符集 基本集》。
- 分区结构(94 区 × 94 位)
- 编码原理:
- 区位码 → 国标码 → 机内码
- 实际使用 87 个区(6763 汉字 + 682 符号)
GB/T 2312 中对所收汉字进行了分区处理,每区含有 94 个汉字或符号,共计 94 个区。实际上,GB/T 2312 只使用了 87 个区。
用所在的区和位来表示字符的方法称为区位码,即码位。
在 GB2312 内,每个汉字及符号的码位使用两个字节来表示。第一个字节称为高位字节,对应分区的编号;第二个字节称为低位字节,对应区段内的码位。
兼容 ASCII
GB 2312 遵循 ISO 2022 规范,为了避开 ASCII 字符中的不可显示字符
0x00至0x1F及空格字符0x20,非 ASCII 字符双字节编码范围为0x21 0x21至0x7E 0x7E,十进制为33 33至126 126。因此,在进行码位转换时,须将区码和位码分别加上 32 或
0x20作为国标码。因为国标码和通用的 ASCII 码冲突,部分厂商在 ISO 2022 的基础上把双字节字符的二进制最高位都从 0 换成 1,即相当于把 ISO 2022 的每个字节都再加上 128 或
0x80得到机内码表示,简称内码。
# GBK(1995)
汉字内码扩展规范,简称 GBK,由中华人民共和国全国信息技术标准化技术委员会制订。
- 扩展特性:
- 21886 字符(21003 汉字 + 883 符号)
- 微软兼容实现
- 技术特点:
- 双字节扩展编码
- 兼容 GB2312 的实现方式
由于 GB 2312-80 只收录了 6763 个汉字,有不少汉字没有收录在内。于是厂商微软利用 GB 2312-80 未使用的编码空间,收录 GB 13000.1-93 全部字符制定了 GBK 编码。
兼容 GB2312
GBK 向下完全兼容 GB2312-80 编码。
# GB18030(2000)
GB 18030,全称《信息技术 中文编码字符集》,是中华人民共和国国家标准所规定的变长多字节字符集。
强制标准特性:
- 变长编码(1/2/4字节)
- 少数民族文字支持
- Unicode 映射关系
兼容性
对 GB 2312-1980 完全向后兼容,与 GBK 基本向后兼容,并支持 GB 13000 的所有码位。
# 三、编码转换机制
# Quoted-printable
Quoted-printable 是使用可打印的 ASCII 字符表示各种编码格式下的字符,以便能在 7-bit 数据通路上传输 8-bit 数据。
- 实现原理:
- 8-bit 数据转 7-bit 可打印字符
- 等号转义机制(=XX)
- 应用场景:
- 电子邮件编码
- 二进制数据文本化
任何 8-bit 字节值可编码为 3 个字符:一个等号 = 后跟随两个十六进制数字表示该字节的数值。
除了可打印 ASCII 字符与换行符以外,所有字符必须表示为这种格式。
所有可打印 ASCII 字符可用 ASCII 字符编码来直接表示,但是等号 = 不可以这样直接表示。
# 百分号编码
百分号编码,又称 URL 编码,是特定上下文的统一资源定位符 URL 的编码机制。
# 编码规范
URI 所允许的字符分作保留与未保留。保留字符是那些具有特殊含义的字符,例如,斜线字符用于不同部分的分界符;未保留字符没有这些特殊含义。
百分号编码把保留字符表示为特殊字符序列。
- 保留字符转义机制(%XX)
- 非 ASCII 字符处理流程: 字符 → UTF-8 → 十六进制转义
百分号编码一个保留字符,首先需要把该字符的 ASCII 的值表示为两个 16 进制的数字,然后在其前面放置转义字符 %,置入 URI 中的相应位置。
对于非 ASCII 字符,需要转换为 UTF-8 字节序,然后每个字节按照上述方式表示。
# 标准差异
URI (opens new window) 规范和 W3C (opens new window) 规范有部分内容不一致。
例如空格,URI 规范将其转为 %20,W3C 规范将其转为 +。
- RFC 3986 规范:
- 空格转为
%20 - 严格 URI 编码规则
- 空格转为
- W3C 规范:
- 空格转为
+ - 表单数据编码实践
- 空格转为
# Reference
[^1]: 弯引号,又称智能引号或印刷引号,由 Microsoft 软件的 "smart quotes" 功能产生,位于 Windows-1252 中 0x91-0x94 范围内。