背景

这篇blog是和python2中让人抓狂的编码异常做个了断。

仔细读了以下文档:

编码异常以及Python 2 的str和unicode

character:表示文本的最小的不可分割字符,例如”A”, “饕”,”È”等。

code point:是一个整数(注意仅仅是数值,并没有限制存储上需要几个字节),通常用16进制表示,和character能够对应起来。

unicode标准:定义了character和code point之间的mapping。

屏幕上的字符:是专门的图形表示元素glyph通过程序渲染的效果。

换言之,屏幕上看到的字符的表示(character),对应一个code point(整数),并且对应一个特定的字符(抽象意义)。

encoding: 把unicode字符串转化为字节数组,注意这里并不确定具体按照什么规则转化、怎么转化,是固定用4个字节,还是用8个字节,或者用变长,encoding没有明确这个规则。

编码(以utf-8为例):定义了encoding的规则,也就是unicode字符串和字节数组之间如何相互转化,utf-8是一种变长的规则。

ascii编码:只支持0-127,如果一个code point的值超过127,encoding时就会报UnicodeEncodeError。

1
2
3
4
5
>>> u'羁绊是什么意思'.encode('ascii')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-6: ordinal not in range(128)
>>>

UTF-8的特点:变长,支持所有unicode code point,没有0字节,比较鲁棒(能够识别出一个字节是否是code point的开始)。

上面的例子用utf-8编码:

1
2
3
>>> u'羁绊是什么意思'.encode('utf-8')
'\xe7\xbe\x81\xe7\xbb\x8a\xe6\x98\xaf\xe4\xbb\x80\xe4\xb9\x88\xe6\x84\x8f\xe6\x80\x9d'
>>>
1
2
3
4
5
6
7
8
9
>>> unicode('abcdef' + chr(255))    
Traceback (most recent call last):
...
UnicodeDecodeError: 'ascii' codec can't decode byte 0xff in position 6:
ordinal not in range(128)
>>> unicode('\x80abc', errors='replace')
u'\ufffdabc'
>>> unicode('\x80abc', errors='ignore')
u'abc'

后记

基本上看完官方文档,就能清楚python2中unicode和str的区别,以及处理常见的编码问题了,所以到这就戛然而止了。