本文中出现的所有数字均为自然书写(低位在右)。
本文中出现的所有字节流均为小地址在左。
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 字节变长存储。因此,从 Unicode 2.0 开始,代理项对被禁止对应任何字符。
在 UTF-16 的处理过程中,计算机通常将 2 个字节的 UTF-16 解码成 1 个 Unicode。代理项对的出现指示计算机需要将 4 个字节的 UTF-16 解码成 1 个 Unicode。具体的转换方式详见后文 UTF-16 BE 部分。
平面
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)。
存储方式:
# | 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-16 BE
这是一种 Unicode 的 2、4 字节变长存储方式。
编码方法:
若 Unicode 位于
U+0
和U+FFFF
之间:- 按照自然顺序书写(低位在右),将 Unicode 转换成二进制编码,在左边用
0
将其补足成16位,然后按照 8 bit 切分字节,左侧为小地址,构成 UTF-16 BE。
- 按照自然顺序书写(低位在右),将 Unicode 转换成二进制编码,在左边用
若 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
之间。- 按照自然书写顺序,将结果转换成二进制编码,在左侧用0补足成16位,然后按照字节切分,构成 UTF-16 BE 的二进制形式
0b01011111 0b00100000
(十六进制形式0x5F 0x20
)。
例2:
U+1F604
(字符😄
)位于U+10000
和U+10FFFF
之间。- 减去
0x10000
,得0xF604
,转换成二进制编码0b 0001 1111 0110 0000 0100
- 填入二进制编码
0b 111101 10 00000100
,得到 UTF-16 BE 的二进制形式0b11011000 0b00111101 0b11011110 0b00000100
(十六进制形式0xD8 0x3D 0xDE 0x04
)。
UTF-16 LE
- 2 字节 UTF-16:UTF-16 LE 和 UTF16-BE 完全相同。
- 4 字节 UTF-16:首先生成 UTF-16 BE 并将其平均分为2组,然后将每组的2个字节交换位置,这样就可以得到 UTF-16 LE。
UTF-32
UTF-32 BE
这是一种 Unicode 的 4 字节定长存储方式。
编码方法:
- 按照自然顺序书写(低位在右),将 Unicode 转换成二进制编码,在左边用
0
将其补足成32位,然后按照 8 bit 切分字节,左侧为小地址,构成 UTF-32 BE。
例1:
U+5F20
(字符张
)转换成二进制编码0b 0101 1111 0010 0000
。- 用
0
将其补足成32位,得到 UTF-32 BE 的二进制形式0b00000000 0b00000000 0b01011111 0b00100000
(十六进制形式0x00 0x00 0x5F 0x20
)。
例2:
U+1F604
(字符😄
)转换成二进制编码0b 0001 1111 0110 0000 0100
- 用
0
将其补足成32位,得到 UTF-32 BE 的二进制形式0b00000000 0b00000001 0b11110110 0b00000100
(十六进制形式0x00 0x01 0xF6 0x04
)。
UTF-32 LE
将 UTF-32 BE 整体翻转字节顺序,即可得到 UTF-32 LE。
UCS
UCS 是 Universal Character Set(通用字符集)的简称。
UCS 标准由国际标准化组织(ISO)制定。在最新标准中,UCS 将字符与0x0
至0x10FFFF
之间的数字一一对应,最多可以表示1114112个字符。
UCS 的地位等同于 Unicode,两者也基本相同(同一字符对应的 Unicode 值与 UCS 值是相等的)。不同之处在于:UCS中的0xD800
至0xDFFF
区域有对应的字符,而 Unicode(2.0+版本)将其定义为代理项对而不对应任何字符。
UCS-2 标准与 UCS-4 标准由国际标准化组织(ISO)制定。UCS-2 与 UCS-4 都是 UCS 的存储映像,关系如同 UTF 和 Unicode。
UCS-2
UCS-2 是一种 UCS 的 2 字节定长存储方式,该标准已经过时。
UCS-2 与 UTF-16 BE 相似。两者的差别在于:UCS-2 只支持基本多文种平面,而 UTF-16 支持所有平面。
由于 UCS 与 Unicode(2.0+版本)在0xD800
至0xDFFF
区间采用了不同的编制方法,所以 UTF-16 在兼容 UCS-2 的同时,也存在着冲突。(不过大多数软件能够将 UTF-16 中错误的代理项对当作 UCS-2 来理解,将冲突减少到最低。)
摘自 Unicode 官网 - https://unicode.org/faq/utf_bom.html#utf16-11
Q: What is the difference between UCS-2 and UTF-16?
A: UCS-2 is obsolete terminology which refers to a Unicode implementation up to Unicode 1.1, before surrogate code points and UTF-16 were added to Version 2.0 of the standard. This term should now be avoided.
UCS-2 does not describe a data format distinct from UTF-16, because both use exactly the same 16-bit code unit representations. However, UCS-2 does not interpret surrogate code points, and thus cannot be used to conformantly represent supplementary characters.
Sometimes in the past an implementation has been labeled "UCS-2" to indicate that it does not support supplementary characters and doesn't interpret pairs of surrogate code points as characters. Such an implementation would not handle processing of character properties, code point boundaries, collation, etc. for supplementary characters.
UCS-4
UCS-4 是一种 UCS 的 4 字节定长存储方式,与 UTF-32 BE 完全相同。
字节顺序
字节顺序(字节序,端序,Endianness,Byte Endianness)是指:在计算机科学领域中,是跨越多字节的程序对象的存储规则。
在几乎所有的机器上,多字节对象都被存储为连续的字节序列。而存储地址内的排列则有两个通用规则。对于一个多位的整数,如果包含最低有效位在字节存放在小地址,则称小端序(little-endian,LE);反之则称大端序(big-endian,BE)。
自然书写一个二进制/十六进制整数,按照 8 bit 切分字节,若将右侧视为小地址则为小端序。
Unicode 就是一个多位整数,因此在编码为 UTF-16 和 UTF-32 时,有 BE 和 LE 两种编码方式。由于 UTF-8 是非对称的,所以只有唯一的编码方式。
在网络应用中,字节序是一个必须被考虑的因素,因为不同机器类型可能采用不同标准的字节序,所以均要按照网络标准转化为大端序。
PS:区别字节序与位序(Bit endianness)。位序指单字节内部各个位的存储规则。由于位序属于CPU架构的底层且各个计算机差别不大,因此用的非常少。本文不涉及位序。
字节顺序标记
字节顺序标记(Byte Order Mark,BOM)位于文档开头,用于文件的编码方式以及字节顺序。
编码 | 字节流(小地址在左) |
---|---|
UTF-8 | 0xEF 0xBB 0xBF |
UTF-16 BE 和 UCS-2 BE | 0xFE 0xFF |
UTF-16 LE 和 UCS-2 LE | 0xFF 0xFE |
UTF-32 BE 和 UCS-4 BE | 0x00 0x00 0xFE 0xFF |
UTF-32 LE 和 UCS-4 LE | 0xFF 0xFE 0x00 0x00 |
示例
U+5F20
(字符张
)
格式 | 字节流(小地址在左) |
---|---|
UTF-8 | 0xE5 0xBC 0xA0 |
UTF-16 BE 和 UCS-2 BE | 0x5F 0x20 |
UTF-16 LE 和 UCS-2 LE | 0x20 0x5F |
UTF-32 BE 和 UCS-4 BE | 0x00 0x00 0x5F 0x20 |
UTF-32 LE 和 UCS-4 LE | 0x20 0x5F 0x00 0x00 |
U+1F604
(字符😄
)
格式 | 字节流(小地址在左) |
---|---|
UTF-8 | 0xF0 0x9F 0x98 0x84 |
UTF-16 BE | 0xD8 0x3D 0xDE 0x04 |
UTF-16 LE | 0x3D 0xD8 0x04 0xDE |
UTF-32 BE 和 UCS-4 BE | 0x00 0x01 0xF6 0x04 |
UTF-32 LE 和 UCS-4 LE | 0x04 0xF6 0x01 0x00 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。