编码知识小结

 

编码知识小结

最早的编码是ascii,它只在1-127,用一个字节就可以表示出来。并且这个字节的第一个位是0。

后来,很多国家的语言发现ascii表示的字符太少,比如中文是不可能表示了来的,所以每个国家都发展了自己的扩展编码,如中国的gb2312,台 湾的big5,日本的shift-jis等。各个国家的扩展编码有一点是相同的,就是都采用了最大长度为2的变长编码,这主要是为了和ascii保持兼 容。其编码规范一般是,对于ascii里的字符,保持和ascii编码兼容的格式,也就是第一个位是0,但是对于各国自己的文字,采用两个字节来表示,两 个字节能表示的字数是2^16=65535个,这一般来说是够了。采用的作法一般是让字节的第一位为1,这样,计算机看到字符的首字符为1,就会认为这是 个扩展的编码,会把接下来跟着的一个字符加到一起,两个字符当作一个字来处理。

gb2312就是这样一个最大长度为2的可变长编码,gb2312共收录了7445个字符,其中汉定6763个,它的编码范围为2121H-777EH,可以看出,gb2312并没有全部使用这两个字节的空间,它是可以再扩充的。

gbk就是在gb2312基础上再扩充的。因为gb2312定义的6000多个汉字越来越不够用了,所以出现了gbk编码,gbk保持和 gb2312的兼容,在此基础上,增加了另一些不常见的汉字符号等。gbk中共收入21886人汉字和符号。gbk也是一种最大长度2字节的变长编码,它 的编码范围为8140-FEFE之间。

其它国家的扩展编码(big5, shift-jis)等也都是采用和gb2312/gbk一样的思路,使用最大两字节的变长编码,因为这样可以和ascii保持兼容。

但是,中国的汉字其实不只这些,还有一些特别不常见的汉字,加一起一共好象有7万多个,超过了两字节能表示的范围。这种情况下,又产生了gb18030编码。

gb18030是一个最大长度为4字节的可变长编码,它向下和gb2312,gbk保持兼容,另外它又扩展了很多的字符,总共超过了7万个,这样 gb18030的编码长度可能是1,2,4字节,对于gb2312,gbk兼容的部分,它使用两字节表示,当两字节不够用的时候,它使用4字节编码。 gb18030的编码空间约有160万码位,上前已编码2万多个。gb18030的范围:一字节部分从0x0-0x7F与ascii兼容,二字节部分,首 字节从0x81-0xfe,尾字节从0x40-0x7e以及0x80-0xfe,与gbk兼容。四字节部分,第一字节从0x81-0xfe,第二字节从 0x30-0x39,第三和第四字节的范围和前两个字节分别相同,四字节部分覆盖了从0x0080开始,除去二字节部分已经覆盖的所有 Unicode3.1码位,也就是说,gb18030编码在码位空间上做到了与Unicode标准一一对应。

虽然各国都定义了自己的编码,但是互相之间是不通用的,因为大家都只有两字节共65535个位置可以使用,大家都用这一段区域,但是又没有形成统 一,比如你用哪段我用哪段,所以互相的编码是不统一的,一段gb2312的编码拿到shift-jis上解析就变成乱码了。这种情况下,为了统一,产生了 Unicode编码。

Unicode定义了百万个以上的字符,包括了各个国家的编码里有的字符(如gb2312,gbk,big5等),如果把所有的字符用统一的格式表 示,需要4个字节,实际上,这就是UTF32,Linux下就是使用UTF32方案。但是分析一下其实大部分字符都可以使用2个字节表示,这样可以节省空 间,比如Widnows上就是用两个字节的Unicode方案,也叫UTF16,在UTF16里,对于两个字节不能表示的的字符,使用一种代理的手法来扩 展(其实就是在低两个字节上做一个标记,表示这是一个代码,需要连接上随后的两个字节,才能组成一个字符)。所以,一般来说,在Windows平台上提到 Unicode就是指UTF16,而在Linux下面提到Unicode是指UTF32。

Unicode的学名叫"Universal Multiple-Octer Coded Character Set",简称UCS,UCS是"Unicode Character Set"的缩写,所以UCS其实就是指Unicode。Unicode规范的字符的编码,UCS规定了怎么用多个字节表示字符。

UCS有两种格式:UCS2和UCS4,UCS2就是用两个字节编码,UCS4就是4个字节(实际上只用了31位,最高位必须为0)。

UCS2和UCS4都是定长的编码,UCS2有2^16=65535个码位,UCS4有2^31=2147483648个码位。

UCS4根据最高位为0的最高字节分为2^7=128个group,每个group根据次高字节分为256个plane,每个根据第3字节分为 256行,每行包含256个cells。group 0的plane 0被称为Basic Multilingual Plane,即BMP。也就是说UCS2其实只能表示UCS4中BMP的部分。对于BMP的UCS2和UCS4编码的转换很简 单,UCS2->UCS4,只要在编码前两加个全是0的字节,而UCS4->UCS2就是把编码的前两个全为0的字节去掉。UCS2也就只能 表示BMP时而定义的<=65535个字符。不过,上前的UCS4规范还没有字符被分配在BMP之外。(好象新的标准已经有在BMP之外的了吧,要 不然gb18030那些扩展字符在BMP里应该是放不下的)。

Unicode是一种编码方式,要把Unicode用于实际中还需要对Unicode进行编码(UCS虽然好,但是它是不适合保存到文件系统中的。 因为ascii转换成UCS2,只是在编码前加一个0x0,用这些编码会出现一些控制符,比如/等,这在unix和一些c函数中,会产生严重错误。),这 就产生了UTF-7,UTF-8,UTF-16,UTF-32。

utf-8是一种8位的字符集,编码长度是可变的,从1个字节到6个字节不等,utf-8保持和ascii的兼容。一般来说,utf-8用一个字节 表示ascii字符,用两个字节表示西欧字符,用三个字符表示亚洲的大部分字符。Unix平台普遍支持utf-8,大部分html,以及文件存储,传输等 都使用utf-8。

utf-16也是一种变长编码,但是它不和ascii兼容。utf-16是ucs2的超集,它实际上是ucs2加上附加字符的支持,也就是符合 Unicode4.0规范的UCS2。utf16至少使用2个字节表示一个字符,在ucs2之外附加的字符部分使用4个字节表示。所以utf-16要么是 2个字节,要么是4个字节。utf-16是windows平台上主要使用的编码方案,主要在windows2000以上版本使用。windows下的 wchar_t就是两个字节,应该就是utf-16。

utf-32是一种定长编码,它和UCS4几乎是相同的。utf-32编码每个码使用4个字节,linux下使用的是utf-32方案。

utf是编码方案,所以还涉及到字节序的问题。字节顺序标记(Byte Order Mark, 简称BOM)出现在Unicode流开端,说明编码类型。BOM是一个有点小聪明的想法:在UCS编码中有一个叫做"zero width no-break space"的字符,编码为FEFF,而FFFE在UCS中是不存在的字符,所以不应该出现在实际的传输中,UCS规范建议我们在传输字节流前,先传 输"zero width no-break space",这样拉收者收到这个字符时就可以通过它判断字节顺序。下面是常用的BOM:

> UTF-16 big endian FE FF
> UTF-16 little endian FF FE
> UTF-32 bign endian 00 00 FE FF
> UTF-32 little endian FF FE 00 00
> UTF-8 little endian EF BB BF

当我们在Unicode流开头读到这些字符时就可以确认编码的顺序。utf-8因为是以字节为单位进行编码,所以不存在字节顺序问题,但可以用 BOM来表示编码方式,字符"zero width no-break space"的utf-8编码是EF BB BF。所以如果收到EF BB BF开头的字节流,就表明这是utf-8编码。在windows下,如果用记事本存一下utf-8格式的文件,其头部就是以EF BB BF开头的。在linux下,为了保持和ascii的兼容,所有的utf-8文件是不加EF BB BF头的。

UTF-8设计之中的一个优点是它将一组码点编码成字节流,而不是WORDS或者DWORDS,这样可以忽略底层机器的字节序(endian)问 题。这意味着你可以在两台小尾字节序和大尾字节序的机器之间交换UTF-8流而不需要任何字节重组或添加BOM。也就是说,你可以完全无视底层的体系架 构。

UTF-8编码的另一个优点源于它从左到右存储实际码点的比特,做一个二进制形式的原始字节排序,就可以将字符串按码点排序。这虽然不如按 locale排序规则进行排序那么好,但对于无需理解UFF-8的底层系统来说,它终究提供了很简易的一种排序方式,底层系统只需要知道如何排序原始字节 就可以了。

总结:

Unicode是规范,其有UCS2和UCS4两种格式。UCS2和UCS4都是定长的。基本上可以理解为UCS4就是UTF-32,而UCS2和UTF-16兼容,只是UTF-16扩展了一些。

UTF是Unicode的实现,它分为utf-8,utf-16,utf-32几种形式,其中utf-8和utf-16都是变长的,而utf-32是定长编码。(其实还有utf-7等其它编码存在)

附:UTF-8的字节布局:

> 字节数 位数 表示
> 1 7 0bbbbbbb
> 2 11 110bbbbb 10bbbbbb
> 3 16 1110bbbb 10bbbbbb 10bbbbbb
> 4 21 11110bbb 10bbbbbb 10bbbbbb 10bbbbbb
> 5 26 111110bb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb
> 6 31 1111110b 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb
> 7 36 11111110 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb
> 8 42 11111111 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb 10bbbbbb

你可能感兴趣的:(other)