原文链接:http://blog.jobbole.com/50345/#article-comment
字节流 vs Unicode对象
我们先来用Python定义一个字符串。当你使用string类型时,实际上会储存一个字节串。
Python
[ a ][ b ][ c ] = “abc”
[ 97 ][ 98 ][ 99 ] = “abc”
1
2
[ a ][ b ][ c ] = “abc”
[ 97 ][ 98 ][ 99 ] = “abc”
在这个例子里,abc这个字符串是一个字节串。97.,98,,99是ASCII码。Python 2.x版本的一个不足之处就是默认将所有的字符串当做ASCII来对待。不幸的是,ASCII在拉丁式字符集里是最不常见的标准。
ASCII是用前127个数字来做字符映射。像windows-1252和UTF-8这样的字符映射有相同的前127个字符。在你的字符串里每个字节的值低于127的时候是安全的混合字符串编码。然而作这个假设是件很危险的事情,下面还将会提到。
当你的字符串里有字节的值大于126的时候就会出现问题了。我们来看一个用windows-1252编码的字符串。Windows-1252里的字符映射是8位的字符映射,那么总共就会有256个字符。前127个跟ASCII是一样的,接下来的127个是由windows-1252定义的其他字符。
A windows-1252 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 150 ] = "abc–"
1
2
A windows-1252 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 150 ] = "abc–"
Windows-1252仍然是一个字节串,但你有没有看到最后一个字节的值是大于126的。如果Python试着用默认的ASCII标准来解码这个字节流,它就会报错。我们来看当Python解码这个字符串的时候会发生什么:
Python
x = “abc” + chr(150)
print repr(x)
‘abc\x96’
u”Hello” + x
Traceback (most recent call last):
File “”, line 1, in ?
UnicodeDecodeError: ‘ASCII’ codec can’t decode byte 0x96 in position 3: ordinal not in range(128)
1
2
3
4
5
6
7x = “abc” + chr(150)
print repr(x)
‘abc\x96’
u”Hello” + x
Traceback (most recent call last):
File “”, line 1, in ?
UnicodeDecodeError: ‘ASCII’ codec can’t decode byte 0x96 in position 3: ordinal not in range(128)
我们来用UTF-8来编码另一个字符串:
A UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"
[0x61] [0x62] [0x63] [0xe2] [ 0x80] [ 0x93] = "abc-"
1
2
3
A UTF-8 encoded string looks like this:
[ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"
[0x61] [0x62] [0x63] [0xe2] [ 0x80] [ 0x93] = "abc-"
如果你拿起看你熟悉的Unicode编码表,你会发现英文的破折号对应的Unicode编码点为8211(0x2013)。这个值大于ASCII最大值127。大于一个字节能够存储的值。因为8211(0x2013)是两个字节,UTF-8必须利用一些技巧告诉系统存储一个字符需要三个字节。我们再来看当Python准备用默认的ASCII来编码一个里面有字符的值大于126的UTF-8编码字符串。
Python
x = “abc\xe2\x80\x93”
print repr(x)
‘abc\xe2\x80\x93’
u”Hello” + x
Traceback (most recent call last):
File “”, line 1, in ?
UnicodeDecodeError: ‘ASCII’ codec can’t decode byte 0xe2 in position 3: ordinal not in range(128)
1
2
3
4
5
6
7x = “abc\xe2\x80\x93”
print repr(x)
‘abc\xe2\x80\x93’
u”Hello” + x
Traceback (most recent call last):
File “”, line 1, in ?
UnicodeDecodeError: ‘ASCII’ codec can’t decode byte 0xe2 in position 3: ordinal not in range(128)
你可以看到,Python一直是默认使用ASCII编码。当它处理第4个字符的时候,因为它的值为226大于126,所以Python抛出了错误。这就是混合编码所带来的问题。
解码字节流
在一开始学习Python Unicode 的时候,解码这个术语可能会让人很疑惑。你可以把字节流解码成一个Unicode对象,把一个Unicode 对象编码为字节流。
Python需要知道如何将字节流解码为Unicode对象。当你拿到一个字节流,你调用它的“解码方法来从它创建出一个Unicode对象。
你最好是尽早的将字节流解码为Unicode。
Python
x = “abc\xe2\x80\x93”
x = x.decode(“utf-8”)
print type(x)