本文中出现的所有数字均为自然书写(低位在右)。
本文中出现的所有字节流均为低地址字节在左。
Unicode
Unicode 标准由统一码联盟(The Unicode Consortium)制定。
Unicode 将字符与0x0
至0xD7FF
之间、0xE000
至0x10FFFF
之间的数字一一对应。最多可以表示 1112064 个字符。
Unicode 字符通常使用 U+十六进制数
表示。
代理项对
0xD800
至0xDFFF
之间的数字用于构建代理项对(surrogates pair):
-
0xD800
至0xDCFF
称为高代理项(high surrogates)。 -
0xDD00
至0xDFFF
称为低代理项(high surrogates)。
代理项对的意义是实现 UTF-16 的 2、4 字节变长存储。因此,代理项对被禁止对应任何字符。
在 UTF-16 的处理过程中,计算机通常将 2 个字节的 UTF-16 解码成 1 个 Unicode。代理项对的出现指示计算机需要将 4 个字节的 UTF-16 解码成 1 个 Unicode。具体的转换方式详见后文 UTF-16 部分。
平面
Unicode 被划分为 0-16 共 17 个平面(plain),每个平面包含 65536 个字符。
将 Unicode 右移 2 字节即可得到所在平面的编号。
其中U+0
至U+FFFF
所在的第 0 平面称为基本多文种平面(Basic Multilingual Plane,BMP)。
UTF
Unicode 仅仅指定了字符与数字的映射关系,并没有指定其实际存储方式。Unicode 的存储方式称为 UTF。
UTF 全称 Unicode Transform Format,是 Unicode 的转换格式。
UTF 标准由统一码联盟(The Unicode Consortium)制定。
UTF-8
UTF-8 是一种 Unicode 的 1-4 字节变长存储方式,向下兼容 ASCII(ISO-646)和 ANSI(扩展 ASCII ,ISO-8859‐1‐1987,Latin-1)。
存储方式:
# | Unicode | bit 容量 | 字节流 |
---|---|---|---|
1 | U+0 至U+7F | 7 | 0b0xxxxxxx |
2 | U+80 至U+7FF | 11 | 0b110xxxxx 0b10xxxxxx |
3 | U+800 至U+FFFF | 16 | 0b1110xxxx 0b10xxxxxx 0b10xxxxxx |
4 | U+10000 至U+10FFFF | 21 | 0b11110xxx 0b10xxxxxx 0b10xxxxxx 0b10xxxxxx |
编码方法:
- 将 Unicode 转换成二进制编码。
- 对比二进制编码的位数和 bit 容量,选择合适的编码方式。
- 从右往左,依次用二进制编码填入字节流中的
x
,不足的位补0
。
例1:
-
U+5F20
(字符张
)转换成二进制编码0b 0101 1111 0010 0000
。 - 二进制编码的位数为15,选择编码方式3。
- 将
0b 101 111100 100000
填入,得到 UTF-8 的二进制形式0b11100101 0b10111100 0b10100000
(十六进制形式0xE5 0xBC 0xA0
)。
例2:
-
U+1F604
(字符?
)转换成二进制编码0b 0001 1111 0110 0000 0100
。 - 二进制编码的位数为17,选择编码方式4。
- 将
0b 11111 011000 000100
填入,得到 UTF-8 的二进制形式0b11110000 0b10011111 0b10011000 0b10000100
(十六进制形式0xF0 0x9F 0x98 0x84
)。
UTF-16
UTF-16BE
这是一种 Unicode 的 2、4 字节变长存储方式。
编码方法:
-
若 Unicode 位于
U+0
和U+FFFF
之间:- 将结果转换成二进制编码,直接构成 UTF-16BE。
-
若 Unicode 位于
U+10000
和U+10FFFF
之间,则:- 减去
0x10000
; - 将结果转换成二进制编码。
- 从右往左,依次用二进制编码填入下列字节流中的
x
,不足的位补0
。 - 字节流
0b110110xx 0bxxxxxxxx 0b110111xx 0bxxxxxxxx
。
- 减去
代理项对:
-
0b110110xx 0bxxxxxxxx
称为高代理项(存放 Unicode 的高位),位于0xD800
至0xDCFF
之间。 -
0b110111xx 0bxxxxxxxx
称为低代理项(存放 Unicode 的低位),位于0xDD00
至0xDFFF
之间。
例1:
-
U+5F20
(字符张
),位于U+0
和U+FFFF
之间。 - 将结果转换成二进制编码,直接构成 UTF-16BE 的二进制形式
0b01011111 0b00100000
(十六进制形式0x5F 0x20
)。
例2:
-
U+1F604
(字符?
)位于U+10000
和U+10FFFF
之间。 - 减去
0x10000
,得0xF604
,转换成二进制编码0b 0001 1111 0110 0000 0100
- 填入二进制编码
0b 111101 10 00000100
,得到 UTF-16BE 的二进制形式0b11011000 0b00111101 0b11011110 0b00000100
(十六进制形式0xD8 0x3D 0xDE 0x04
)。
UTF-16LE
首先将 UTF-16BE 分为2组,然后将每组的2个字节交换位置,这样就可以得到 UTF-16LE。
UTF-32
UTF-32BE
这是一种 Unicode 的 4 字节定长存储方式。
编码方法:
- 将 Unicode 转换成二进制编码,用
0
将其补足成32位,构成 UTF-32BE。
例1:
-
U+5F20
(字符张
)转换成二进制编码0b 0101 1111 0010 0000
。 - 用
0
将其补足成32位,得到 UTF-32BE 的二进制形式0b00000000 0b00000000 0b01011111 0b00100000
(十六进制形式0x00 0x00 0x5F 0x20
)。
例2:
-
U+1F604
(字符?
)转换成二进制编码0b 0001 1111 0110 0000 0100
- 用
0
将其补足成32位,得到 UTF-32BE 的二进制形式0b00000000 0b00000001 0b11110110 0b00000100
(十六进制形式0x00 0x01 0xF6 0x04
)。
UTF-32LE
将 UTF-32BE 整体翻转字节顺序,即可得到 UTF-32LE。
UCS
UCS 是 Universal Character Set(通用字符集)的简称。
UCS 标准由国际标准化组织(ISO)制定。在最新标准中,UCS 将字符与0x0
至0x10FFFF
之间的数字一一对应,最多可以表示1114112个字符。
UCS 的地位等同于 Unicode,两者也基本相同(同一字符对应的 Unicode 值与 UCS 值是相等的)。不同之处在于:UCS中的0xD800
至0xDFFF
区域有对应的字符,而 Unicode 将其定义为代理项对而不对应任何字符。
UCS-2 和 UCS-4
UCS-2 标准与 UCS-4 标准由国际标准化组织(ISO)制定。UCS-2 与 UCS-4 都是 UCS 的存储映像,关系如同 UTF 和 Unicode。
UCS-2
UCS-2 是一种 UCS 的 2 字节定长存储方式。
UCS-2 与 UTF-16BE 相似。两者的差别在于:UCS-2 只支持基本多文种平面,而 UTF-16 支持所有平面。
由于 UCS 与 Unicode 在0xD800
至0xDFFF
区间采用了不同的编制方法,所以 UTF-16 在兼容 UCS-2 的同时,也存在着冲突。(不过大多数软件能够将 UTF-16 中错误的代理项对当作 UCS-2 来理解,将冲突减少到最低。)
UCS-4
UCS-4 是一种 UCS 的 4 字节定长存储方式,与 UTF-32 完全相同。
字节顺序
字节顺序(字节序,端序,Endianness,Byte Endianness)是指:在计算机科学领域中,是跨越多字节的程序对象的存储规则。
在几乎所有的机器上,多字节对象都被存储为连续的字节序列。而存储地址内的排列则有两个通用规则。对于一个多位的整数,如果最低有效位在最高有效位的前面,则称小端序(little-endian,LE);反之则称大端序(big-endian,BE)。
Unicode 就是一个多位整数,因此在编码为 UTF-16 和 UTF-32 时,有 BE 和 LE 两种编码方式。由于 UTF-8 是非对称的,所以只要唯一的编码方式。
在网络应用中,字节序是一个必须被考虑的因素,因为不同机器类型可能采用不同标准的字节序,所以均要按照网络标准转化为大端序。
PS:区别字节序与位序(Bit endianness)。位序指单字节内部各个位的存储规则。由于位序属于CPU架构的底层且各个计算机差别不大,因此用的非常少。本文不涉及位序。
字节顺序标记
字节顺序标记(Byte Order Mark,BOM)位于文档开头,用于文件的编码方式以及字节顺序。
编码 | 字节流 |
---|---|
UTF-8 | 0xEF 0xBB 0xBF |
UTF-16BE 和 UCS-2 BE | 0xFE 0xFF |
UTF-16LE 和 UCS-2 LE | 0xFF 0xFE |
UTF-32BE 和 UCS-4 BE | 0x00 0x00 0xFE 0xFF |
UTF-32LE 和 UCS-4 LE | 0xFF 0xFE 0x00 0x00 |
示例
U+5F20
(字符张
)
格式 | 字节流 |
---|---|
UTF-8 | 0xE5 0xBC 0xA0 |
UTF-16BE 和 UCS-2 BE | 0x5F 0x20 |
UTF-16LE 和 UCS-2 LE | 0x20 0x5F |
UTF-32BE 和 UCS-4 BE | 0x00 0x00 0x5F 0x20 |
UTF-32LE 和 UCS-4 BE | 0x20 0x5F 0x00 0x00 |
U+1F604
(字符?
)
格式 | 字节流 |
---|---|
UTF-8 | 0xF0 0x9F 0x98 0x84 |
UTF-16BE 和 UCS-2 BE | 0xD8 0x3D 0xDE 0x04 |
UTF-16LE 和 UCS-2 LE | 0x3D 0xD8 0x04 0xDE |
UTF-32BE 和 UCS-4 BE | 0x00 0x01 0xF6 0x04 |
UTF-32LE 和 UCS-4 BE | 0x04 0xF6 0x01 0x00 |