Python食谱-1.20.使用Unicode 处理国际化文本
| 原文作者: | Holger Krekel |
|---|---|
| 中文翻译: | Tony (digitalsatori) |
问题
如何处理包含'非ASCII'字符的文本字符串。
解决方法
在普通字节码字符串类型出现的地方都可以使用 Python 的first class Unicode类型。当你了解什么时候需要做字节码字符串和Unicode字符串之间的转换时,一切就变得容易了。
>>> german_ae = unicode('\xc3\xa4', 'utf8')
这里的german_ae是一个unicode字符串,表示德文字符"ae"-带有重音符号的小写字母a。它是用指定的UTF-8编码来解析字节码字符串 \xc3\xa4 而获得。字符编码方式有很多,但UTF-8是最经常被使用的。因为UTF-8可以为所有的Unicode字符串编码,同时又与7-bit ASCII码完全兼容(任何一个ASCII码字符串也同样是UTF-8编码的字符串)。
一旦突破了这个障碍,就自由了!我们可以象处理普通str字符串那样来处理Unicode字符串:
>>> sentence = "This is a " + german_ae >>> sentence2 = "Easy!" >>> para = ". ".join([sentence, sentence2])
注意这里的para是一个Unicode 字符串,因为当在字节码字符串和unicode字符串之间操作时,除了以下抛出异常的情况,总是会返回一个unicode字符串:
>>> bytestring = '\xc3\xa4' # 非-ASCII码字符串 >>> german_ae += bytestring UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)
字节码 '0xc3' 在7-bit ASCII编码中不是一个有效的字符,Python不会去猜测其所使用的编码。所以明确指定编码方式是Python中使用Unicode字符串的关键。
讨论
如果我们遵循规则并学会通用的应对方法,那么Python中的Unicode 处理也是很简单的。最重要的一点是,要了解字节码字符串和unicode字符串之间的区别。正如本配方中的例子所示,我们往往通过一个字节码字符串及其编码方式来创建相应的unicode字符串。没有指定编码方式,字节码字符串对于unicode字符串是没有意义的,除非你够幸运,恰好那个字节码字符串是用ASCII码编码的。
在使用Python的Unicode字符串时碰到最多的问题就是要处理既有字节码字符串又有Unicode字符串的情况。Python隐式地将字节码转换为Unicode字符串的尝试中,一般会假设字节编码为ASCII码。当字节码字符串中有‘非ASCII码’字符串时,就会抛出 UnicodeDecodeError 异常。``UnicodeDecodeError`` 表明代码中混有Unicode字符串和字节码字符串,Python无法猜测字节码字符串所使用的编码。
做过大型Python项目的程序员总结出了防止程序在运行期间抛出 UnicodeDecodeErrors 异常的方法,概括起来一句话:总是在输入/输出(IO)界面上做转换。这句话的意思是:
在程序从外部(来自网络,文件,用户输入,等等)接收到文本数据时,立即将其转变为unicode字符串对象。当然首先要了解其编码方式,比如,通过HTTP的头文件,或者其它决定编码的约定。 在程序向外部(至网络,文件,用户界面,等等)发送文本数据时,设置正确的编码,并立即按编码将文本转换为字节码字符串。(否则,Python会尝试将Unicode转换为ASCII编码的字节码字符串,很可能会导致 UnicodeEncodeErrors 异常,正好与此前提到的 UnicodeDecodeErrors 相反。)
遵循以上两条规则,可以解决绝大多数的Unicode相关的问题。如果仍然有任何的UnicodeErrors, 请检查是否正确创建unicode对象,或是否正确将unicode对象转换为字节码字符串。将Unicode字符串转换为字节码字符串的方法如下:
>>> bytestring = german_ae.decode('latin1')
>>> bytestring
'\xe4'
在上例中的 bytestring 就是以'latin1'编码的德语字符 'ae'。请注意, \xe4 (latin1编码)和之前的 \xc3\xa4 (UTF-8编码)表示同一个德文字符,但是使用不同的编码。
至此,你大概就了解了为什么Python不会从几百个不同的编码方式中猜测字符串的编码方式。这是Python的一个重要的设计取向,正如Python之禅(the Zen of Python)中所总结的:“面对含糊莫名,不做无谓猜测“。在交互式Python shell环境中输入 import this 来了解Python之禅的更多内容。
参见
Unicode是一个很大的话题,推荐阅读 《Unicode: A Primer》 ,作者 Tony Graham (Hungry Minds, Inc 发行); 还有一篇 Joel Spolsky 写的短小精湛的文章, 名为 "The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses)!,"
另外,请参考Python库参考手册和Python in a Nutshell中关于内置函数str, unicode类型 ,以及unidata模块和codecs的内容。另外,请参考 Python食谱1.21 和 Python食谱1.22 的内容。














[...] Python食谱1.200 [...]
[...] codecs 和 site 模块,以及 sys 模块中的 setdefaultencoding 函数; Python食谱1.20 Python食谱1.21 网络书签 [...]