2014年7月31日星期四

字符编码小结

首先需要记住一件事情,那就是计算机中存储的一定是二进制数,是浮点,有符号数,还是无符号数或者是代码完全取决于你如何处理这些二进制,即运算规则。这里只是关心这些二进制数跟文字之间的关系,也就是不同的二进制数如何映射到文字的,或者反过来。

有一个术语用来表示不同的文字和二进制数之间的关系:字符编码。简单的来说字符编码就是把一堆文字映射到一堆数字的标准。这也就是说同样一个二进制数在不同的字符编码中就表示不同的数字。例如对于汉字就有GB2312,GBK,GB18030,GB13000,BIG5等等,所有这些编码方法都是用于在计算机中存储汉字,如果文件使用的编码和计算机解释用的编码不一样,那就形成了“乱码”现象。 在汉字的编码中GB2312最先出现,然后依次出现GBK,GB18030,GB13000,后面的编码对前面的编码兼容,也就是说同一个汉字的二进制数是一样的。BIG5是台湾、香港等地使用的字符编码,和其他的字符编码是不兼容的,同时GB18030兼容GBK、GB2312编码,但是GB13000好像就是Unicode的标准,和其他的其他的字符编码是不兼容的。现在考虑另外一个事情:windows和linux的locale。简单的来说locale就是用本地的方式来显示一些信息,一般来说是时间和货币单位等等,当然也包括文字,这是很大的不同。所以locale中的字符编码决定了默认使用什么字符编码来对文件中的信息进行解码,如果相同或者兼容还好,不同的话肯定就乱码了。

但是随着Unicode的出现,这个问题以另一种方式被解决了:使用同一个字符集,这个字符集包含了所有语言的所有文字,所以大家就不同担心了。但是新的问题又出现了。Unicode为每个字符分配了一个码位,可以认为是逻辑上的一个二进制数,但是如何在现实中表示则有不同的方法。明显一个字节只有8位,所有当二进制数的位数大于8时,必然要使用超过一个字节来表示,这些不同的字节之间存在什么关系呢?这就是UTF-8,UTF-16,UTF-32。UTF-8兼容ASCII,使用变长编码,这就意味着可以使用C的库函数来处理UTF-8。UTF-8对于C语言来说不过是一堆比较怪异的ASCII而已。UTF-16使用双字节,不同表示全部的Unicode字符,而且还有大端、小端的区别。在文件的前两个字节中(0xEE,0xFF)的不同排列所显示出来。 UTF-32,使用四个字节,可以完全表示UCS,但是用的很少。如果现在所有的文件都使用UTF-8或者UTF-16,那么世界上很多问题就没了(很明显不是)。所以经常需要做字符编码之间的转码,可以使用iconv来完成这个操作,使用file命令获取文件的原始编码。如果从小的字符集向大的字符集转,没有任何问题,如果从大的字符集向小的字符集转,有些字符无法表示,就转换失败了。对于汉字还有另外一个特殊的情况。使用file对使用GB2312,GBK,GB18030编码的汉字文件进行探测时,返回的是ISO-8859这个编码,这个时候可以直接按照GB18030解码(对于其他编码是兼容的),可 以获得正确的结果!

没有评论:

发表评论