python的中文编码问题

  刚申了博客园的博客,刚好这几天在做一件很累人的事情,老板叫我们把word里的一些公式、字段变成excel里的。好像有几百个文档,很累人。懒人当惯了,于是私下写了个python脚本完成了任务。学习了python操作MS office的API,很好用的。在写脚本的时候遇到的最大的问题是中文编码问题,以前注意过python解决internationalize的办法,没用忘光了。这次系统地学习了一下,做一个总结吧。

1、Unicode

      关于Unicode,主要要理解code point的概念,指的是相应的数值,也即“位置”,和character不是同个概念,只是一个code point定义了一个相应的character。而character要存储在内存或者磁盘中需要进行编码encoding,而编码方式可以有很多,比如说UTF-8、UTF-16、UTF-32等。UTF-8、UTF-16、UTF-32都是Unicode的编码方式,覆盖了所有的代码点(code point),这样一个character对应的字节数不一定是一个字节,可能对应多个字节。

      以前我有个误区,java内部使用UTF-16编码,以为Unicode就是16bits的。其实这是两个概念,unicode是指整套的编码系统,从代码点到编码方式,而UTF-16也不一定只是16bits,对于大部分常用character,是16bits编码的,对于有些不常用的可能是32bits编码的,否则无法覆盖所有的代码点。

      这里特别提一下UTF-8编码,个人觉得使用UTF-8编码是个好习惯,当然也有人建议使用UTF-16也可以。UTF-8具体的编码算法推荐看一下,用它编码出对应一个character的字节串是没有0x00字节的,这个就可以和C语言的字符串的以0x00结尾兼容了,那些字符串的库函数就可以使用了。

  还有一点值得提的是BOM(byte order mark),字节序标记。一般放在文本开头,用以区分字节流的大小端存储模式。

  大家如果有什么问题,可以去参考下面的推荐链接,说得都很易懂,可以帮助你理解。

2、字节流和字符流

  计算机中文件是以0、1的二进制存储的,所以字节流和字符流都是一个一个字节的序列。只是在读取和写入的时候,对于字节流,以字节为单位读取写入,所以具体的字节含义需要自己程序去理解。而字符流则是以字符为单位读取写入的,一个字符可能对应多个字节。可以这样理解,字符流是在字节流上增加了一层编码解码,它帮你理解了字节序的意思。常见的open函数(C语言),open(filename , "r")表明是以字符流方式读写文件,open(filename, “rb”)表明以字节方式读写。当然,在C的open函数中,默认的编码方式是ASCII,所以字符流也是一个字节为单位读取(这是因为一个字符对应一个字节),在windows下,‘\n’会被存储为'\r\n',读入的时候'\r\n'又变成了'\n'。如果按字节流读写就没上述情况了('\r\n'读入还是'\r\n')。

  在python中我们可以用codecs模块下的open方法来指定特定编码的字符流读写。

3、python编码问题

  1)、python内部使用的是Unicode编码,具体在内存中是按UTF-8编码格式存储的。

  2)、一个python源文件的文件编码方式是可以任意的,python在解释的时候会根据相应的编码转化变成内部的unicode。

  3)、python在不知道编码方式的情况下,会以ASCII为默认编码方式转化。

  比如一个源文件的编码方式“gb2312”(常用中文编码方式),那么python在解释源文件的时候先把源文件转化为Unicode,然后再编码为UTF-8在内存中存储。这里就涉及到如何告知python源文件的编码方式。类似于HTML等,需要在源文件的开头声明编码方式的,具体的声明方式可以参考http://www.python.org/peps/pep-0263.html 。所以python在解释源文件的时候,会先按默认的ASCII编码解析转化,在遇到该声明的时候重新按声明的编码方式解析转化。(所以声明一般放在前两行)

  对于字符串,python有两种类型:str类型和unicode类型,都继承者basestring,对于strl类型,是指在特定编码方式下的“字节序列”。而unicode类型可以这样理解,是指"代码点序列"。

  比如

      a = '中国' 和 b=u'中国'                                                                                                                           

  python在给赋值的时候对于前者,直接是原编码方式“gb2312”的字节序,而后者会把内存中的UTF-8转化为Unicode的代码点序列。

  于是前者是str类型,后者是unicode类型                                                                                                      

  前者的值为'\xd6\xd0\xb9\xfa'                                                                                                                

  后者的值为u'\u4e2d\u56fd'                                                                                                                    

  用查看他们的大小可知:                                                                                                                          

  len(a) --->  4                                                                                                                                      

  len(b) --->  2                                                                                                                                      



4、总结

  写得有点乱,很多东西没讲到,比如说python如何编码解码(用decode、encode方法),这些网上资料很多,我这里只是说了一下自己以前在编码方面认识的误区,所以也不是很系统地写,而且上述说的可能也有错误的地方,敬请指正。

  最后推荐几个链接,很有用的,我都看过,而且很通俗易懂,希望还有问题的可以参考一下:

      The [...] Minimum Every Software Developer [...] Must Know About Unicode [...] by Joel Spolsky - Another essay about why Unicode is good, and an introduction to how it works.  


  On the Goodness of Unicode by Tim Bray - An essay about why you should support Unicode.


    Characters vs. Bytes  by Tim Bray - An introduction to the details of Unicode encoding. 


      Unicode HOWTO

 

posted @ 2011-09-23 19:33  楼昊  阅读(650)  评论(0)    收藏  举报