Python2字符编码

字符编码

我们通常见到的字符串编码主要是三种GB2312/GBK、Unicode、UTF-8。GB2312/GBK是多字节(multibytes)编码的一种,属于“ASCII的加强版”,与之平行的由Big5、ShiftJIS之类的编码各自为政。为了避免这个问题,Unicode应运而生,将全世界所有的字符统一编码到一个定长的结构中。Unicode解决了统一编码的问题,但带来了新的问题。第一点,Unicode和ASCII不兼容了,这是因为ASCII只有一个字节,而这一个字节肯定装不下Unicode。第二点,用Unicode传输开销变大了,这是因为很多文档二十六个字母(1个字节)就能解决了,用Unicode多了很多冗余的字节。因此UTF-8应运而生。UTF-8对Unicode进行变长编码(我们可以想象下Huffman树),通常长度在1-4字节。目前Linux系统使用的是UTF-8编码,而Windows内部则是UTF-16LE/GBK编码。

Python2的字符串表示

Python2中有表示字符串有str和unicode两种。

1
2
3
4
5
6
7
8
>>> "你好"
'\xc4\xe3\xba\xc3'
>>> u"你好"
u'\u4f60\u597d'
>>> type("你好")
<type 'str'>
>>> type(u"你好")
<type 'unicode'>

其中unicode得益于ucs2/ucs4标准,在不同系统上都是固定的表示的,而str的表示取决于所在的系统,例如Linux是默认UTF8,上面的“你好”就会变为'/xe4/xbd/xa0/xe5/xa5/xbd',我们这里看到UTF8确实是一种字符的表示。

1
2
3
4
5
6
7
8
9
10
11
>>> "hello".encode("utf-8")
'hello'
>>> "hello".decode("gbk").encode("utf-8")
'hello'

>>> "你好".encode("utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 0: ordinal not in range(128)
>>> "你好".decode("gbk").encode("utf-8")
'\xe4\xbd\xa0\xe5\xa5\xbd'

伪装成unicode的多字节

有时候我们会看到这种东西u'\xe3\x80\x8a\xe5',首先这外面套了个u,应该是unicode,但是里面却是\x打头的multi-bytes的形式,这往往是由于错误调用unicode()函数所致的。对此,python提供了raw_unicode_escape来解决这个问题