最近断断续续和几个机油在写一个邮件查看器一类的东西,中间遇到了很多编码问题,想起来 Python 里的编码问题一直就没大搞清楚,趁这次出问题刚好研究了一下。

首先,我们要简单知道一下编码,编码相当于对字符的映射。简单来说,编码有 ASCII 码、 Unicode、 GB等, ASCII 码本身一共128个,无法表示所有的文字,所以 Unicode 这时就出现了,Unicode 通过拓展编码长度的方式拓展了其字符集,UTF-8是其中的一个实现,而 GB 标准是对汉字的一个专用编码,我们通常说道的 GBK 是它的一个拓展。我们一般见到的汉字是 GBK 或者 UTF-8 编码的,UTF-8 作为国际编码通用性更高,在多数时候不大会出问题,但缺点就是相对于拓展了国家标准的 GBK,占用的空间较大。

好了,简单了解了编码,我们转到 Python 里来,我这里是 Python27。Python 支持非 ASCII 字符集,不过我们要实现去声明,通常我们见到的# -*- coding: utf-8 -*-就是对选用字符集的声明。

通常我们输入一个字符串,可以有个两种类型<type 'str'><type 'unicode'>:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
>>> s = '中文'
>>> s
'\xd6\xd0\xce\xc4'
>>> type(s)
<type 'str'>
>>> len(s)
4
>>> s = u'中文'
>>> type(s)
<type 'unicode'>
>>> s
u'\u4e2d\u6587'
>>> len(s)
2

其中<type 'str'>是将字符串看作字节的序列,而<type 'unicode'>是将字符串看作字符的序列。对于一般情况下,把中文字符串保存为 unicode 类型的最好的,这样便于我们进行字符串切片的操作,也方便我们对不同字符集的转换。

<type 'str'>可以通过合适的decode()或者unicode()来变成<type 'unicode'>,而<type 'unicode'>可以通过合适的encode()来变成<type 'str'>,我们可以对 unicode 字符串进行各种转码操作,可以说,unicode 是 python 字符串编码中的一个重要的中间类型。

1
2
3
4
5
6
7
8
9
10
>>> s = '中文'
>>> s
'\xd6\xd0\xce\xc4'
>>> s.decode('gbk')
u'\u4e2d\u6587'
>>> unicode(s, 'gbk')
u'\u4e2d\u6587'
>>> s = u'中文'
>>> s.encode('gbk')
'\xd6\xd0\xce\xc4'

而在跨平台的过程之中,我们通过locale.setlocale(locale.LC_ALL, '')可以获取当前系统的编码值,然后再根据系统的编码,对字符串进行编码。

最后在提一下 PyQt 中的 QString 和 QByteArray,这些是因为 PyQt 作为 Qt 的承接,为了与 C++ 中字符串一致创造的,其中 QString 与 unicode 相当,而 QByteArray 与 str 相当。

拓展阅读:
字符编码笔记:ASCII,Unicode和UTF-8 阮一峰的网络日志
Unicode in Python 2.x Docs Python Documentation
Sequence Types — str, unicode, list, tuple, bytearray, buffer, xrange Python Documentation
Where is my Character? unicode.org
GB 汉字内码扩展规范 wiki