Tags: unicode, Time: 2018-05-05 17:31:08

总结了下常见的字符集和它们之间的关系。

1、ASCII码

ASCII的全称是American Standard Code for Information Interchange(美国信息交换标准代码),是基于拉丁字母的一套电脑编码系统,用于显示现代英语。定义了128个字符,其中33个字符不可显示,这33个字符大多已经作废。

2、GB18030

ASCII 解决了现代英语在电脑中的显示问题,但中文怎么显示呢?中国国家标准总局在1981年发布了 GB2312,对任意一个字符都采用2个字节来表示,收录了6763个汉字,GB 2312 的编码范围为 2121H-777EH,与 ASCII 有重叠,通行方法是将 GB 码两个字节的最高位置 1 以示区别。

GBK 其中 K 是扩展的意思,主要是为了解决因为 GB2312 不能处理人名和古汉语的罕见字的问题。GBK 收录了21886 个汉字,采用两个字节表示,向下兼容 GB2312。

GB18030 是国家最新标准,收录了 70244 个汉字,和 UTF-8 一样采用变长字符编码,每个字可以由 1 个、2 个或 4 个字节组成,兼容 GB2312 和 GBK,单字节于 ASCII 兼容。

3、Unicode

GB18030 可以显示简体中文,台湾和香港采用BIG-5显示繁体中文,日本又有自己的字符集,各自访问国内站点都可以,但一旦访问别国的网站就出现乱码了,可不可以统一编码解决乱码问题呢?答案是肯定的。

Unicode 是为整合全世界的所有语言文字而诞生的。任何文字在 Unicode 中都对应一个值,这个值称为代码点(code point)。代码点的值通常写成 U+ABCD 的格式。而文字和代码点之间的对应关系就是 USC-2(Universal Character Set coded in 2 octets)。顾名思义,UCS-2是用两个字节来表示代码点,其取值范围为 U+0000~U+FFFF。

为了能表示更多的文字,人们又提出了 UCS-4,即用四个字节表示代码点。UCS-4规划的范围是0x0000-0x10FFFF,17个平面,每个平面有65536个码点。最常见的是平面0(Basic Multilingual Plane即BMP)65536 个码点(即 0x0000 至 0xFFFF),超出 BMP 的字符以 UTF-16 或 UTF-8 编码都需要4字节。

USC-4 中 BMP 去掉高位的两个 0 就是 UCS-2,比如 UCS-2 中定义 字二进制是 0100 1110 0010 1101,BMP中是 00 0100 1110 0010 1101。

要注意,UCS-2 和 UCS-4 只规定了代码点和文字之间的对应关系,并没有规定代码点在计算机中如何存储。规定存储方式的称为 UTF(Unicode Transformation Format),其中应用较多的就是 UTF-16 和 UTF-8 了。

4、UTF-8

字的 Unicode 码是 0x4e2d,二进制是 0100 1110 0010 1101,需要用两个字符来存储,而英文只需要单字节,如果都用两个字节来存储的话,对于英文系统就是很大的浪费。UTF-8 定义了变长存储的方法。

UTF-8 的编码规则很简单,只有二条:

1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。

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

下表总结了编码规则,字母 x 表示可用编码的位。

Unicode符号范围(十六进制) UTF-8编码方式(二进制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

以中为例,中的unicode是 4e2d,属于第三行范围内,将二进制填进去就是 11100100 10111000 10101101,转成十六进制就是:E4B8AD。

5、UTF-16

UTF-16 使用二或四个字节为每个字符编码,其中大部分汉字采用两个字节编码,少量不常用汉字采用四个字节编码。UTF-16 编码有大尾序和小尾序之别,即 UTF-16BE 和 UTF-16LE,在编码前会放置一个 BOM(U+FEFF 或 U+FFFE)来表示是大尾还是小尾。

6、BOM

BOM英文全称是“byte order mark”,它是 Unicode 字符编码方案中的一个特殊字符,它是作为辅助之用的字符,而不是一个可打印字符。

BOM 的作用:

1)表明编码得到字节流采用的是大端序,还是小端序。一个Unicode字符可以使用1个字节,2个字节或者4个字节进行编码,在采用2个字节或者4个字节进行编码时,又可以使用大端序或者小端序,在一个处理程序接收到这样的字节流后,可以通过字节流的最前面的字节序列,即BOM字符的字节序列采用的是大端序还是小端序,来获知编码得到该字节流时使用的是大端序还是小端序。

2)表明编码得到字节流有很大可能性采用了Unicode编码方案。

3)表明具体采用哪个Unicode编码方案。在不同的Unicode编码方案中,BOM字符对应的字节序列不一样,基于该点,根据获得的BOM字符的字节序列,可以推测出所采用的Unicode编码方案。

Unicode编码方案中的BOM:

UTF-8 中,BOM 字符对应的字节序列是“0xef,0xbb,0xbf”。在 UTF-8 中,不推荐使用 BOM 字符,因为在使用UTF-8编码方案编码得到的字节流中,很容易就可以根据一些字符对应的特殊的字节序列而检测出所使用的编码方案是UTF-8。UTF-8 一直使用大端序,不使用小端序。

UTF-16中,BOM 字符对应的字节序列是“0xfe 0xff”(这是小端序,大端序是“0xff 0xfe”)。

UTF-32中,BOM 字符对应的字节序列是“0x00 0x00 0xfe 0xff”(这是小端序,大端序是“0xff 0xfe 0x00 0x00”)。

7、参考文章

字符编码笔记:ASCII,Unicode 和 UTF-8 —— 阮一峰

BOM字符