ansi, gbk, unicode等各种

先说python的事。

python 2.x处理unicode路径时一定要把所有用到字符串的地方全弄成unicode,否则中途可能会出现非常莫名其妙的错误。

os.listdir()接受unicode作为参数时返回的list会自动将所有串解码成unicode,os.join()接受unicode作为参数时没有问题,但是如果接受的参数里头既有unicode又有utf-8的话就会发生一些非常奇异的问题。

windows的FAT32和NTFS对文件名的存储都是unicode的。所以向os传递字符串时直接使用unicode是最保险的。

这几天为了写一个纠正编码的程序,好好地去把unicode、utf-8和本地编码的区别看了一下。

首先是ASCII。话说很久之前米国人觉得反正E文就26*2个字母,加上数字也不过62个,再加上标点符号什么的也不会超过100个,于是他们规定用一个8位二进制数(0-127)来表达所有他们需要的字符,这就是ASCII码。

后来中国人日本人开始用电脑了,他们发现电脑字符的ASCII编码居然只有128位,中文和日文怎么都有一千来个字符,没办法全部映射到这里头去。于是他们就想,要不我用两个ASCII字符来表达一个字吧。这就是ANSI系的编码的由来。非unicode的编码都属于这种两个ASCII表示一个字的类型,例如GB2312(GBK,GB18030),Big5,Shift-JIS,EUC-JIS等。每个编码方式都有不同的计算映射的方法,而不同的编码之间不会相互兼容。

这样的事情本来挺好,但是当各国需要交流,尤其是某岛国的某些软件需要在全世界范围内流行的时候,问题来了。如果编码方式错误,那么系统不仅不能正确找出对应的文字符号,而且可能出现其他问题。例如在Shift-JIS和GBK中都存在\x5C这个字符。而这个字符在C系的语言之中是Escape字符,如果没有正确处理这种情况的话,那么就会出现乱码。而且还有一个问题,就是一种编码方式中定义的字符在另一种编码方式中不一定存在。比如GB2312中没有繁体字和日文汉字,而Shift-JIS中没有中国简体字等。如果在Shift-JIS内码的系统上使用中文版的东西,那就是一个蛋疼,反之亦然——而且,希望简单地将中文映射为Shift-JIS里头的文字也由于上面的原因不可行。

人们意识到,编码不统一是一件极其蛋疼的事情。于是一群人就起来想弄一个能表示全世界所有文字的统一编码,这就是Unicode。当然Unicode据说还有个小故事,据说当年想搞统一编码的公司其实有两个,一个是Unicode,另一个是ISO,后来他们终于意识到这个世界只需要一种统一编码,最终Unicode采用了ISO的编码方案。

Unicode的特殊之处在于他是一个符号表。它对于汉字的分类是按照形态划分的。在中日韩三种不同语言中,汉字的写法可能会略有差异,但只要是同一个字符,在Unicode中就只有一个编码。Unicode表是真正的世界通用,表达了包含象形文字在内的几乎所有可被记录下来的文字。所以理论上,如果所有程序都用上这么一个东西,那么编码问题将不复存在。

实际上,Unicode存在两种格式。一种是UCS-2,使用2字节进行字符表示,它已经可以表示所有CJK汉字。另一种格式是UCS-4,使用4字节进行表示,可以表示更多的奇奇怪怪的字符。目前UCS-4仅仅是UCS-2前面增加两个空字节。

但是事情没这么简单。Unicode是一张巨大无比的字符映射表,将每个字符映射为一个16位二进制数(UCS-2)。但是它并没有规定这个二进制数要以什么样的方式存储。比如对于一篇只有英文的文章,整篇文章的所有字符如果用Unicode来表示,那么每个字符的前12位二进制数都是0,这是非常浪费存储空间的。

于是世界上有了UTF-8,UTF-16等不同存储方式。具体细节请google,总之UTF-8是将每个字符的Unicode码以不同的方式变长压缩成为一个串再存储到文件之中去的。其优点在于对英文文章,UTF-8存储占用的空间和ANSI相同,而对于汉字,则可能会使用1,2或者3字节来存储。

在Python 2.x内部,Unicode和str是两个不同的类。str默认为ansi,不管是GB2312,Shift-JIS还是UTF-8都是str类的。而Unicode则单列出来。据说到了Python3,所有的字符串都是unicode了,我们也就没有了文章一开始的蛋疼。

2013-01-24 09:33393