Unicode

Unicode

Unicode(中文:万国码、国际码、统一码、单一码)是计算机科学领域里的一项业界标准。它对世界上大部分的文字系统进行了整理、编码,使得电脑可以用更为简单的方式来呈现和处理文字。Unicode 是为了解决传统的字符编码方案的局限而产生的,例如 ISO 8859-1 所定义的字符虽然在不同的国家中广泛地使用,可是在不同国家间却经常出现不兼容的情况。Unicode 伴随着通用字符集(Universal Character Set)的标准而发展,至今仍在不断增修,每个新版本都加入更多新的字符。目前最新的版本为 2016 年 6 月 21 日公布的 9.0.0,已经收入超过十万个字符。Unicode 备受认可,并广泛地应用于电脑软件的国际化与本地化过程。有很多新科技,如 XML、Java 编程语言以及现代的操作系统,都采用 Unicode 编码。

Unicode 的实现方式不同于编码方式。一个字符的 Unicode 编码是确定的。但是在实际传输过程中,由于不同系统平台的设计不一定一致,以及出于节省空间的目的,对 Unicode 编码的实现方式有所不同。Unicode 的实现方式称为 Unicode 转换格式(Unicode Transformation Format,简称为 UTF)。Unicode 的实现方式有 UTF-8、UTF-16,另外还包括 UTF-7、Punycode、CESU-8、SCSU、UTF-32、GB18030 等,这些实现方式有些仅在一定的国家和地区使用,有些则属于未来的规划方式。目前通用的实现方式是 UTF-16 小端序(LE)、UTF-16 大端序(BE)和 UTF-8。在微软公司 Windows XP 附带的记事本(Notepad)中,“另存为”对话框可以选择的四种编码方式除去非 Unicode 编码的 ANSI(对于英文系统即 ASCII 编码,中文系统则为 GB2312 或 Big5 编码)外,其余三种为“Unicode”(对应 UTF-16 LE)、“Unicode big endian”(对应 UTF-16 BE)和“UTF-8”。

可以这样理解:Unicode 是字符集,UTF-32/ UTF-16/ UTF-8 是三种字符编码方案。

UTF-8

UTF-16

UTF-32

优点

直接兼容 ASCII;空间利用率高;无字节序问题;

通常情况每个字符占 2 个字节;

每个字符都使用 4 个字节,定位串中第 N 个字符为 O(1);

缺点

变长字节编码,寻找串中第 N 个字符复杂度为 O(N);

存在字节序问题;

空间利用率低;存在字节序问题;

UTF-8

UTF-8 的编码规则:

  • 对于单字节的符号,字节的第一位设为 0,后面 7 位为这个符号的 unicode 码。

  • 对于 n 字节的符号(1<n<5),第一个字节的前 n 位都设为 1,第 n+1 位设为 0,后面字节的前两位一律设为 10。剩下的没有提及的二进制位,全部为这个符号的 unicode 码。

Unicode 符号范围

UTF-8 编码方式

U+0000 → U+007F

0xxxxxxx

U+0080 → U+07FF

110xxxxx 10xxxxxx

U+0800 → U+FFFF

1110xxxx 10xxxxxx 10xxxxxx

U+10000 → U+1FFFFF

11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

以汉字“学”为例,“学”的 Unicode 码值为 U+5b66,处于上面表格的 U+0800 → U+FFFF 段内,因此 UTF-8 编码用三个字节来存储。然后将 U+5b66 从最低位到最高位依次填入到上面格式中的 x,并在多出的高位上补 0 即可。5b66 转换为二进制:01011011 01100110,填入到 1110xxxx 10xxxxxx 10xxxxxx 中的 x 标记位,结果为:11100101 10101101 10100110,这样就得到了“学”的 UTF-8 编码,转换为 16 进制就是 e5ada6。

UTF-16

UTF-16 编码规则:

  • 从 U+D800 到 U+DFFF 的码位(代理区):因为 Unicode 字符集的编码值范围为 0-0x10FFFF,而大于等于 0x10000 的辅助平面区的编码值无法用 2 个字节来表示,所以 Unicode 标准规定:基本多语言平面内,U+D800..U+DFFF 的值不对应于任何字符,为代理区。

  • 从 U+0000 至 U+D7FF 以及从 U+E000 至 U+FFFF 的码位:第一个 Unicode 平面(BMP),码位从 U+0000 至 U+FFFF(除去代理区),包含了最常用的字符。UTF-16 与 UCS-2 编码在这个范围内的码位为单个 16 比特长的码元,数值等价于对应的码位。

  • 从 U+10000 到 U+10FFFF 的码位:辅助平面(Supplementary Planes)中的码位,大于等于 0x10000,在 UTF-16 中被编码为一对 16 比特长的码元(即 32bit,4Bytes),称作 code units called a 代理对(surrogate pair),具体方法是:

    • 码位减去 0x10000, 得到的值的范围为 20 比特长的 0..0xFFFFF(因为 Unicode 的最大码位是 0x10ffff,减去 0x10000 后,得到的最大值是 0xfffff,所以肯定可以用 20 个二进制位表示),写成二进制形式:yyyy yyyy yyxx xxxx xxxx。

    • 高位的 10 比特的值(值的范围为 0..0x3FF)被加上 0xD800 得到第一个码元或称作高位代理(high surrogate), 值的范围是 0xD800..0xDBFF。由于高位代理比低位代理的值要小,所以为了避免混淆使用,Unicode 标准现在称高位代理为前导代理(lead surrogates)。

    • 低位的 10 比特的值(值的范围也是 0..0x3FF)被加上 0xDC00 得到第二个码元或称作低位代理(low surrogate), 现在值的范围是 0xDC00..0xDFFF。由于低位代理比高位代理的值要大,所以为了避免混淆使用,Unicode 标准现在称低位代理为后尾代理(trail surrogates)。

    • 最终的 UTF-16(4 字节)的编码(二进制)就是:110110yyyyyyyyyy 110111xxxxxxxxxx。

BOM

字节顺序标记(英语:byte-order mark,BOM)是位于码点 U+FEFF 的统一码字符的名称。当以 UTF-16 或 UTF-32 来将 UCS/统一码字符所组成的字符串编码时,这个字符被用来标示其字节序。它常被用来当做标示文件是以 UTF-8、UTF-16 或 UTF-32 编码的记号。

字符 U+FEFF 出现在字节流的开头,则用来标识该字节流的字节序,是高位在前还是低位在前。对于 GB 2312、GBK、GB 18030、Big5,其编码某个汉字产生的字节顺序,由其编码方案本身决定,不受 CPU 字节序的影响。UTF-8 无字节序问题。

编码

表示(十六进制)

表示(十进制)

UTF-8

EF BB BF

239 187 191

UTF-16(大端序)

FE FF

254 255

UTF-16(小端序)

FF FE

255 254

UTF-32(大端序)

00 00 FE FF

0 0 254 255

UTF-32(小端序)

FF FE 00 00

255 254 0 0

UTF-7

2B 2F 76 和以下的一个字节:[ 38 | 39 | 2B | 2F ]

43 47 118 和以下的一个字节:[ 56 | 57 | 43 | 47 ]

UTF-1

F7 64 4C

247 100 76

UTF-EBCDIC

DD 73 66 73

221 115 102 115

Unicode 标准压缩方案

0E FE FF

14 254 255

BOCU-1

FB EE 28 及可能跟随着FF

251 238 40 及可能跟随着255

GB-18030

84 31 95 33

132 49 149 51