Python之编码问题介绍
Python之编码问题介绍
菜鸟学Python(4):编码问题
---- 温铭 http://blog.csdn.net/wayne92
学Python以来,遇到不少关于编码方面的问题,总是知其然不知其所以然,糊里糊涂的。今天在邮件列表中看到甘晖问一个编码的问题,有不少高手解释。看了以后霍然开朗,记录一下,以后备查:)
一、(以下为张骏的解释,感谢)
个人认为python对unicode的处理已经相当完善了。
对于python来讲,字符集的处理有两个概念:
1 str 是指带有编码的字符串
2 unicode 是指不带有编码的字符串
这两个概念的相互转换是这样进行的:
str ------> unicode --------> str
decode encode
解码 编码
举个最简单的例子:
>>> a = '中'
>>> a
'/xd6/xd0'
>>> b = u'中'
>>> b
u'/u4e2d'
根据上面的描述,b应该是不进行编码的a的值(反正a就是b带有gbk编码的值)
于是,我们可以得到
>>> a.decode( 'gbk' )
u'/u4e2d'
同样也可以得到
>>> b.encode( 'gbk' )
'/xd6/xd0'
不知道我讲的清楚吗?
另外,甘晖遇到的这个xml解析的问题并不是python对编码集处理的问题。而是python的xml模块pyexpat.pyd不支持非utf-8编码的多字节xml的原因。为什么不支持,是因为xml的标准规范仅仅定义了utf-8做为多字节xml的编码,gbk(gb2312)并不是xml规范中允许的字符集。
因此,我们在处理gbk编码集的xml时,都是先将文件读取出来,然后转换为utf8格式,然后再解析
>>> f = file( r'c:/a.xml' )
>>> buf = f.read()
>>> ubuf = buf.decode( 'gbk' ).encode( 'utf-8' )
>>> xml.parser( ubuf )
...
调用字符串的decode和encode方法有一个好处是,不用显式import codecs模块,更不用lookup特定字符编码的decode和encode函数。但是这种方法不适用于对decode和encode方法多次重复调 用的场合,主要是从代码的执行效率方面考虑的。(这一段是麦田守望者的意见)
二、(以下摘自麦田守望者的blog,感谢)
PS:对Python里面的编码总算有个比较清楚的认识了,为了避免麻烦,自己写程序好文件的时候,都在前面加上# -*- coding: utf-8 -*-为好。
重要补记(二零零六年九月七日下午):
一、上面的例子请在命令行下测试,在IDLE下有些会有错误!!我已经决定再也不用IDLE了,太痛苦了,debug半天才发现是IDLE的bug!!
二、刚才用C扩展Python,发现在Python里面传一个字符串给C,在C中打印,如果其中有中文字符,就会有乱码。(如果你没有在文件中加# -*- coding: utf-8 -*-,就不会有这个问题)
解决方法如下:
PS:(2007.11.29)
环境:mysql(utf8编码),eclipse(utf8编码),windows xp
问题:在mysql中显示为中文,程序select出来在eclipse ebug窗口显示为中文,print为乱码,makedirs后为乱码。
解决:path.decode('utf-8').encode('gbk')
先按utf8解码,再按gbk编码
在mysql里面可以看到字符的二进制编码,很好。这个以前没有注意过
---- 温铭 http://blog.csdn.net/wayne92
学Python以来,遇到不少关于编码方面的问题,总是知其然不知其所以然,糊里糊涂的。今天在邮件列表中看到甘晖问一个编码的问题,有不少高手解释。看了以后霍然开朗,记录一下,以后备查:)
一、(以下为张骏的解释,感谢)
个人认为python对unicode的处理已经相当完善了。
对于python来讲,字符集的处理有两个概念:
1 str 是指带有编码的字符串
2 unicode 是指不带有编码的字符串
这两个概念的相互转换是这样进行的:
str ------> unicode --------> str
decode encode
解码 编码
举个最简单的例子:
>>> a = '中'
>>> a
'/xd6/xd0'
>>> b = u'中'
>>> b
u'/u4e2d'
根据上面的描述,b应该是不进行编码的a的值(反正a就是b带有gbk编码的值)
于是,我们可以得到
>>> a.decode( 'gbk' )
u'/u4e2d'
同样也可以得到
>>> b.encode( 'gbk' )
'/xd6/xd0'
不知道我讲的清楚吗?
另外,甘晖遇到的这个xml解析的问题并不是python对编码集处理的问题。而是python的xml模块pyexpat.pyd不支持非utf-8编码的多字节xml的原因。为什么不支持,是因为xml的标准规范仅仅定义了utf-8做为多字节xml的编码,gbk(gb2312)并不是xml规范中允许的字符集。
因此,我们在处理gbk编码集的xml时,都是先将文件读取出来,然后转换为utf8格式,然后再解析
>>> f = file( r'c:/a.xml' )
>>> buf = f.read()
>>> ubuf = buf.decode( 'gbk' ).encode( 'utf-8' )
>>> xml.parser( ubuf )
...
调用字符串的decode和encode方法有一个好处是,不用显式import codecs模块,更不用lookup特定字符编码的decode和encode函数。但是这种方法不适用于对decode和encode方法多次重复调 用的场合,主要是从代码的执行效率方面考虑的。(这一段是麦田守望者的意见)
二、(以下摘自麦田守望者的blog,感谢)
使用codecs模块,在Python中完成字符编码
字符的编码是按照某种规则在单字节字符和多字节字符之间进行转换的某种方法。从单字节到多字节叫做decoding,从多字节到单字节叫做encoding。在这些规则中经常用到的无非是UTF-8和GB2312两种。
在Python中,codecs模块提供了实现这些规则的方法,通过模块公开的方法我们能够方便地获取某种编码方式的Encoder和 Decoder工厂函数(Factory function),以及StreamReader、StreamWriter和StreamReaderWriter类。
使用“import codecs”导入codecs模块。
codecs模块中重要的函数之一是lookup,它只有一个参数encoding,指的是编码方式的名称,即utf-8或者gb2312等等。如下示例:
>>> import codecs
>>> t = codecs.lookup("utf-8")
>>> print t
(<built-in function utf_8_encode>, <function decode at 0x00AA25B0>, <class encodings.utf_8.StreamReader at 0x00AA0720>, <class encodings.utf_8.StreamWriter at 0x00AA06F0>)
>>> encoder = t[0]
>>> decoder = t[1]
>>> StreamReader = t[2]
>>> StreamWriter = t[3]
lookup函数返回一个包含四个元素的TUPLE,其中T[0]是encoder的函数引用,T[1]是decoder的函数引用,T[2] 是UTF-8编码方式的StreamReader类对象引用,T[3]是UTF-8编码方式的StreamWriter类对象引用相信对Python熟悉 的你肯定知道接下来该怎么用它们了。
codecs模块还提供了方便程序员使用的单独函数,以简化对lookup的调用。它们是:
- getencoder(encoding)
- getdecoder(encoding)
- getreader(encoding)
- getwriter(encoding)
如果我们只是想获取一种utf-8编码的encoder方法,那么只需要这样做:
>>> encoder = codecs.getencoder("utf-8")
另外,对于StreamReader和StreamWriter的简化, codecs模块提供一个open方法。相对于built-in对象File的open方法,前者多了三个参数encoding, errors, buffering。这三个参数都是可选参数,但是对于应用来说,需要明确指定encoding的值,而errors和buffering使用默认值即 可。使用方法如下:
>>> fin = codecs.open("e://mycomputer.txt", "r", "utf-8")
>>> print fin.readline()
这是我的电脑
>>> fin.close()
总结一下,codecs模块为我们解决的字符编码的处理提供了lookup方法,它接受一个字符编码名称的参数,并返回指定字符编码对应的 encoder、decoder、StreamReader和StreamWriter的函数对象和类对象的引用。为了简化对lookup方法的调用, codecs还提供了getencoder(encoding)、getdecoder(encoding)、getreader(encoding)和 getwriter(encoding)方法;进一步,简化对特定字符编码的StreamReader、StreamWriter和 StreamReaderWriter的访问,codecs更直接地提供了open方法,通过encoding参数传递字符编码名称,即可获得对 encoder和decoder的双向服务。
-----------------------------------------------
-----------------------------------------------
重要补记(二零零六年九月七日下午):
一、上面的例子请在命令行下测试,在IDLE下有些会有错误!!我已经决定再也不用IDLE了,太痛苦了,debug半天才发现是IDLE的bug!!
二、刚才用C扩展Python,发现在Python里面传一个字符串给C,在C中打印,如果其中有中文字符,就会有乱码。(如果你没有在文件中加# -*- coding: utf-8 -*-,就不会有这个问题)
解决方法如下:
s=u"欢迎使用rss阅读器"
s=s.encode('gbk')
libConsole.ConsoleOutput(s) # libConsole是用C封装成的一个dll,
# ConsoleOutput(s) 是用C写的一个方法,就是
#一个printf语句
s=s.encode('gbk')
libConsole.ConsoleOutput(s) # libConsole是用C封装成的一个dll,
# ConsoleOutput(s) 是用C写的一个方法,就是
#一个printf语句
PS:(2007.11.29)
环境:mysql(utf8编码),eclipse(utf8编码),windows xp
问题:在mysql中显示为中文,程序select出来在eclipse ebug窗口显示为中文,print为乱码,makedirs后为乱码。
解决:path.decode('utf-8').encode('gbk')
先按utf8解码,再按gbk编码
在mysql里面可以看到字符的二进制编码,很好。这个以前没有注意过