Zack
  • 278

字符编码

本文中出现的所有数字均为自然书写(低位在右)

本文中出现的所有字节流均为低地址字节在左

Unicode

Unicode 标准由统一码联盟(The Unicode Consortium)制定。

Unicode 将字符与0x00xD7FF之间、0xE0000x10FFFF之间的数字一一对应。最多可以表示 1112064 个字符。

Unicode 字符通常使用 U+十六进制数表示。

代理项对

0xD8000xDFFF之间的数字用于构建代理项对(surrogates pair):

  • 0xD8000xDCFF称为高代理项(high surrogates)。
  • 0xDD000xDFFF称为低代理项(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+0U+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+0U+7F 7 0b0xxxxxxx
2 U+80U+7FF 11 0b110xxxxx 0b10xxxxxx
3 U+800U+FFFF 16 0b1110xxxx 0b10xxxxxx 0b10xxxxxx
4 U+10000U+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+0U+FFFF之间:

    • 将结果转换成二进制编码,直接构成 UTF-16BE。
  • 若 Unicode 位于U+10000U+10FFFF之间,则:

    • 减去0x10000
    • 将结果转换成二进制编码。
    • 从右往左,依次用二进制编码填入下列字节流中的x,不足的位补0
    • 字节流0b110110xx 0bxxxxxxxx 0b110111xx 0bxxxxxxxx

代理项对:

  • 0b110110xx 0bxxxxxxxx称为高代理项(存放 Unicode 的高位),位于0xD8000xDCFF之间。
  • 0b110111xx 0bxxxxxxxx称为低代理项(存放 Unicode 的低位),位于0xDD000xDFFF之间。

例1:

  • U+5F20(字符),位于U+0U+FFFF之间。
  • 将结果转换成二进制编码,直接构成 UTF-16BE 的二进制形式0b01011111 0b00100000(十六进制形式0x5F 0x20)。

例2:

  • U+1F604(字符😄)位于U+10000U+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 将字符与0x00x10FFFF之间的数字一一对应,最多可以表示1114112个字符。

UCS 的地位等同于 Unicode,两者也基本相同(同一字符对应的 Unicode 值与 UCS 值是相等的)。不同之处在于:UCS中的0xD8000xDFFF区域有对应的字符,而 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 在0xD8000xDFFF区间采用了不同的编制方法,所以 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
阅读 701更新于 2018-07-28
推荐阅读
目录