我确定有很多关于Unicode和Python的说明,但为了方便自己的理解使用,我还是打算再写一些关于它们的东西。
字节流 vs Unicode对象
我们先来用Python定义一个字符串。当你使用string类型时,实际上会储存一个字节串。
[ 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–"
Windows-1252仍然是一个字节串,但你有没有看到最后一个字节的值是大于126的。如果Python试着用默认的ASCII标准来解码这个字节流,它就会报错。我们来看当Python解码这个字符串的时候会发生什么:
>>> x = "abc" + chr(150)>>> print repr(x)'abc/x96'>>> u"Hello" + xTraceback (most recent call last): File "<stdin>", 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-"
如果你拿起看你熟悉的Unicode编码表,你会发现英文的破折号对应的Unicode编码点为8211(0×2013)。这个值大于ASCII最大值127。大于一个字节能够存储的值。因为8211(0×2013)是两个字节,UTF-8必须利用一些技巧告诉系统存储一个字符需要三个字节。我们再来看当Python准备用默认的ASCII来编码一个里面有字符的值大于126的UTF-8编码字符串。
>>> x = "abc/xe2/x80/x93">>> print repr(x)'abc/xe2/x80/x93'>>> u"Hello" + xTraceback (most recent call last): File "<stdin>", 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抛出了错误。这就是混合编码所带来的问题。
新闻热点
疑难解答