我確定有很多關于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拋出了錯誤。這就是混合編碼所帶來的問題。
新聞熱點
疑難解答