Python2编码问题 1970-01-01 00:00

背景

做Python开发的同学对下面的错误一定很熟悉:

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

这也是Python2的一大黑点啊:)

Python2中有两种字符串类型。分别是strunicode。(Py3已经统一成unicode)

str 是由bytes组成的sequence,unicode是Unicode字符集组成的sequence。

string里的有多种编码方式,比如最常用的ascii和utf-8。想解读string,必需知道string里的character是用哪种编码方式,然后才能进行。

unicode有一个.encode()方法去产生byte strings。bytes strings 有对应的.decode()的方法去生成unicode strings.

牢记一句话: ascii和utf-8是编解码方式,unicode是字符集。

为什么会出现unicode字符集呢?ascii码不够用。

In [8]: a="你好" # Mac下面中文默认为utf-8编码

In [9]: a
Out[9]: '\xe4\xbd\xa0\xe5\xa5\xbd'

In [10]: a.decode("utf-8")
Out[10]: u'\u4f60\u597d'

复现UnicodeEncodeError encode错误

In [11]: b=u"你好"

In [12]: b
Out[12]: u'\u4f60\u597d'

In [13]: "abc{}".format(b)
---------------------------------------------------------------------------
UnicodeEncodeError                        Traceback (most recent call last)
<ipython-input-13-19e1bc96cb52> in <module>()
----> 1 "abc{}".format(b)

UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

上面因为Python默认用ascii对unicode b字符串进行编码了。

In [14]: import sys

In [15]: sys.getdefaultencoding() # py2默认编码方式是ascii
Out[15]: 'ascii'

避免encode错误,需要我们手动指定编码:

In [17]: "abc{}".format(b.encode("utf-8"))
Out[17]: 'abc\xe4\xbd\xa0\xe5\xa5\xbd'

复现UnicodeDecodeError decode错误

In [18]: u"abc{}".format(a)
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
<ipython-input-18-8f4837b78059> in <module>()
----> 1 u"abc{}".format(a)

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)

这种情况也是需要我们手动指定解码方式:

In [19]: u"abc{}".format(a.decode("utf-8"))
Out[19]: u'abc\u4f60\u597d'

使用 sys.setdefaultencoding("utf-8") 解决:

In [20]: reload(sys)
<module 'sys' (built-in)>

In [21]: sys.setdefaultencoding("utf-8")

In [22]: t1="中国"

In [23]: t1
'\xe4\xb8\xad\xe5\x9b\xbd'

In [24]: u"abc{}".format(t1)
u'abc\u4e2d\u56fd'

In [25]: t2=u"中国"

In [26]: "abc{}".format(t2)
'abc\xe4\xb8\xad\xe5\x9b\xbd'

总结

1, UnicodeEncodeError错误,发生在Unicode转换成bytes流的时候出错,需要我们手动指定encode。
2, UnicodeDecodeError错误,发生在bytes流转换成unicode时发生错误,需要我们手动指定decode
3, ascii和utf-8是编解码方式,unicode是字符集,ascii是utf-8的子集。

推荐: http://nedbatchelder.com/text/unipain.html