python编码问题

来源:互联网 发布:mac 如何设置桌面图标 编辑:程序博客网 时间:2024/06/01 10:31

初学Python,遇到很多编码问题,记下来以免将来又忘了,很多东西不懂,都是属于不求甚解,乱下结论,但想到拿出来可以有热心同学指出错误所在,便厚起脸皮了……
首先需要了解Python中有两种字符串(严格地说,似乎不能这么叫)。一种是普通的str对象(每个字符用8bits表示),另一种是unicode字符串,它们可以相互转换。
首先打开pyshell,输入一段代码。

python 代码
 
  1. >>> a = "我"   
  2. >>> b = unicode(a,"gb2312")   
  3. >>> a.__class__   
  4. <type 'str'>   
  5. >>> b.__class__   
  6. <type 'unicode'>   
  7. >>>    

看出来了吧,两种字符串。
再来

python 代码
  1. >>> a   
  2. '/xce/xd2'   
  3. >>> b   
  4. u'/u6211'  

变量a是两个字符,b是一个unicode字符。
关于这两种字符串,Python文档-->LanguageReference-->DataModel-->The standard type hierarchy-->Sequences,有一些Strings,Unicode的描述。
至于

python 代码
 
  1. >>> z = u"我"   
  2. >>> #这种代码,其实什么都不是。   
  3. >>> z.__class__   
  4. <type 'unicode'>   
  5. >>> z   
  6. u'/xce/xd2'  

看到了吧,这个奇怪的东西......
后来在WindowsXP、纯python命令行下试过,得出的结论不同,z的结果变成了u'/u6211',这里完全不应该在pyshell下作试验的,看来还有很多问题尚未理解清楚


再来看看encode,decode
什么情况用encode,什么情况又是decode呢,刚开始总是被搞昏。其实各种本地字符集的英文名是Coded Character Set,要转换为Coded,肯定是要encode了,同样,从里面解出来也应该叫decode……
decode就是把其他编码转换为unicode,等同于unicode函数;encode就是把unicode编码的字符串转换为特定编码。在pyshell里继续:
a是Str类型的,所以再用encode会报错。用print输出时会调用默认编码转换为系统编码?

python 代码
 
  1. >>> a.decode("gb2312")   
  2. u'/u6211'   
  3. >>> print a.decode("gb2312")   
  4. 我   
  5. >>> a.encode("gb2312")   
  6. Traceback (most recent call last):   
  7.   File "<input>", line 1, in ?   
  8. UnicodeDecodeError: 'ascii' codec can't decode byte 0xce in position 0: ordinal not in range(128)  

b是unicode类型,打印时需要先encode(编码)成系统编码

python 代码
 
  1. >>> print b.encode("gb2312")   
  2. 我   
  3. >>> b.encode("gb2312")   
  4. '/xce/xd2'   
  5. >>> b.decode("gb2312")   
  6. Traceback (most recent call last):   
  7.   File "<input>", line 1, in ?   
  8. UnicodeEncodeError: 'ascii' codec can't encode character u'/u6211' in position 0: ordinal not in range(128)  

python里默认的encode和decode是strict模式,所以会直接抛出Error,而Java里是默认replace模式,所以在处理servlet时经常会看到一串?????
在decode时传入第二个参数errors为'replace'可以和Java相同,但总是没成功,还不知道为什么

MySQLDb连接数据库的编码问题
试了很久,无论在connect的时候指定charset='utf8',还是使用set_character_set(),或者执行"SET NAMES UTF8",跟踪到character_set_name()方法返回的都是latin1...再跟代码,似乎就跑到mysql-api里去了,反正最后解决的办法也很简单,就是使用如下方式执行,而不要去拼sql语句……

python 代码
 
  1. >>> sql = "INSERT INTO t_user(name,nickname) values(%s,%s)"   
  2. >>> param = ("张三","张三的昵称")   
  3. >>> cursor.execute(sql,param)  

Python的国际化/i18n问题
使用gettext来实现。其实就是一个文本替换的方式,和java里用ResourceBundle、properties比较类似……
http://wiki.wxpython.org/index.cgi/RecipesI18n有一个recipe,不过代码很旧了,现在python里自带了pygettext.py和msgfmt.py
其实就是把http://blog.donews.com/limodou/archive/2004/06/15/28916.aspx的文章按自己思路组织了一下。
步骤:
1.导入gettext模块

python 代码
 
  1. import gettext   
  2. gettext.install('i18ntest', './locale', unicode=True)  

参数说明:
作用域:用于限定翻译文件的主名
路径:翻译文件所在路径
unicode:使用unicode

2.把代码里需要国际化的文本全部使用_("text")的形式进行替换

3.需要进行国际化处理时,调用

python 代码
 
  1. gettext.translation('i18ntest', './locale', languages=['cn']).install(True)  

来处理。

现在程序写好了,需要生成所需资源文件了:
1.调用python安装目录的 Tools/i18n/pygettext.py抽取所需翻译的模板
>>> pygettext.py path/to/yourfile.py
将生成一个名为messages.pot的文件
2.生成模板文件后,修改这个模板文件,其中的msgid为键值,对应你程序里写的文本,如:_("New File"),而msgstr为翻译后的值。还有就是注意修改文件头部分Content-Type的charset为合适的编码,比如utf8
3.编写好模板后,把扩展名修改为.po,运行Tools/i18n/msgfmt.py,生成二进制的资源文件
>>> msgfmt.py messages.po
将生成一个名为messages.mo的文件
4.把这个mo文件放在正确的位置.
比如你在程序中是这样写的:
gettext.install('i18ntest', './locale', unicode=True)
gettext.translation('i18ntest', './locale', languages=['cn']).install(True)
那么你的程序目录下需要存在./local/cn/LC_MESSAGES/i18ntest.mo
这样程序启动时就会读取这个资源文件,替换对应的文本,实现国际化了。
注意:如果使用utf格式保存,po文件不能有BOM头。cn目录是所对应的语言,LC_MESSAGES目录是gettext.py里要求的,mo文件必须和所定义的域同名,见
gettext.py的mofile = os.path.join(localedir, lang, 'LC_MESSAGES', '%s.mo' % domain)

学习资料

All About Python and Unicode http://boodebr.org/main/python/all-about-python-and-unicode
彻底了解python的编码问题 http://blog.csdn.net/iamjianglibo/archive/2007/02/07/1504819.aspx
Python中文问题研究 http://hi.baidu.com/daping_zhang/blog/item/09dda71ea9d7d21f4134173e.html
MySQLdb带中文参数的问题 http://bbs.chinaunix.net/archiver/?tid-833164.html
wxPython RecipesI18n http://wiki.wxpython.org/index.cgi/RecipesI18n
limodou的blog和ulipad/doc/i18n.htm
http://blog.donews.com/limodou/archive/2004/06/15/28916.aspx
http://blog.donews.com/limodou/archive/2004/06/15/28947.aspx
http://blog.donews.com/limodou/archive/2004/06/15/28961.aspx

 

 

 

原文地址:http://www.javaeye.com/topic/66558

原创粉丝点击