1. 程式人生 > >從python2,python3編碼問題引伸出的通用編碼原理解釋

從python2,python3編碼問題引伸出的通用編碼原理解釋

Coding 理解 不同的 文本處理 解釋 .com alt 問題處理 fontsize

今天使用python2編碼時遇到這樣一條異常UnicodeDecodeError: ‘ascii’ code can’t decode byte 0xef

發現是編碼問題,但是平常在python3中幾乎沒有遇到過,所以特意查了資料,原來python3和python2對於字符串的理解不一樣,在python3中,字符串默認unicode編碼

一.解釋python2和python3文本處理方式

在Python3當中,文本字符串類型(使用Unicode數據存儲)被命名為 str , 字節字符串類型被命名為 bytes 。一般情況下,實例化一個字符串會得到一個 str 對象 :

技術分享圖片

如果你想得到bytes,那就在文本之前加上前綴 b , 或者 encode 一下。

技術分享圖片

所以,很顯然,str 對象有一個encode方法,bytes 對象有一個decode方法。

在Python3中的 str 對象在Python2中叫做 unicode , bytes 對象在Python2中叫做 str

在python2中使用中文字符串的方式是在頁首聲明# *--coding:utf-8--*

技術分享圖片 技術分享圖片

二.常用編碼方式

順便在網上查了一下字符集和編碼方式的文檔,發現很多人都解釋的難以理解,所以這裏嘗試說清楚一下。這裏不解析字符集和編碼方式,統稱為編碼方式。

不論什麽編碼,在計算機中統一是按照二進制字節形式存儲,一個字節有8位

1.ASCII碼,總共有128個,用1個字節的低7位來表示

2.ISO-8859-1,128個字符表示明顯不夠用,所以ISO組織又制訂了新的標準來擴展ASCII碼,它們是ISO-8859-1到ISO-8859-15,其中ISO-8859-1涵蓋了大部分西歐編碼,所以用的最多。ISO-8859-1也是單字節編碼,總共表示256個字符,發現字符變成?時,一般是使用了ISO-8859-1編碼,規定不認識範圍內的使用3f表示的就是?

3.GB2312,雙字節編碼,範圍為A1-F7,其中A1-A9是符號區,包含682個符號,B0-F7是漢字區,包含6763個漢字,漢字使用兩個字節表示

4.GBK,用於擴展GB2312,編碼範圍8140~FEFE,總共有23940個碼位,使用GB2312編碼的漢字可以用GBK來解碼

5.UTF-16,所有字符都是用兩個字節,兩個字節為16bit,所以叫UTF-16,但是浪費空間.(同unicode)

6.UTF-8,每個編碼區域有不同的字碼長度,最長為三個字節,編碼規則如下:

(1)如果一個字節的第一位為0,那麽代表當前字符為單字節字符,占用一個字節的空間。0之後的所有部分(7個bit)代表在Unicode中的序號。
(2)如果一個字節以110開頭,那麽代表當前字符為雙字節字符,占用2個字節的空間。110之後的所有部分(7個bit)代表在Unicode中的序號。且第二個字節以10開頭
(3)如果一個字節以1110開頭,那麽代表當前字符為三字節字符,占用2個字節的空間。110之後的所有部分(7個bit)代表在Unicode中的序號。且第二、第三個字節以10開頭
(4)如果一個字節以10開頭,那麽代表當前字節為多字節字符的第二個字節。10之後的所有部分(6個bit)代表在Unicode中的序號

具體每個字節的特征可見下表,其中x代表序號部分,把各個字節中的所有x部分拼接在一起就組成了在Unicode字庫中的序號

Byte 1Byte 2Byte3
0xxx xxxx
110x xxxx 10xx xxxx
1110 xxxx 10xx xxxx 10xx xxxx

我們分別看三個從一個字節到三個字節的UTF-8編碼例子:

實際字符 在Unicode字庫序號的十六進制 在Unicode字庫序號的二進制 UTF-8編碼後的二進制 UTF-8編碼後的十六進制
$ 0024 010 0100 0010 0100 24
¢ 00A2 000 1010 0010 1100 0010 1010 0010 C2 A2
20AC 0010 0000 1010 1100 1110 0010 1000 0010 1010 1100 E2 82 AC

細心的讀者不難從以上的簡單介紹中得出以下規律:

  • 3個字節的UTF-8十六進制編碼一定是以E開頭的
  • 2個字節的UTF-8十六進制編碼一定是以CD開頭的
  • 1個字節的UTF-8十六進制編碼一定是以比8小的數字開頭的

三.常見問題處理之Emoji

所謂Emoji就是一種在Unicode位於\u1F601\u1F64F區段的字符。這個顯然超過了目前常用的UTF-8字符集的編碼範圍\u0000\uFFFF。Emoji表情隨著IOS的普及和微信的支持越來越常見。下面就是幾個常見的Emoji:

技術分享圖片技術分享圖片技術分享圖片

那麽Emoji字符表情會對我們平時的開發運維帶來什麽影響呢?最常見的問題就在於將他存入MySQL數據庫的時候。一般來說MySQL數據庫的默認字符集都會配置成UTF-8(三字節),而utf8mb4在5.5以後才被支持,也很少會有DBA主動將系統默認字符集改成utf8mb4。那麽問題就來了,當我們把一個需要4字節UTF-8編碼才能表示的字符存入數據庫的時候就會報錯:ERROR 1366: Incorrect string value: ‘\xF0\x9D\x8C\x86‘ for column 。 如果認真閱讀了上面的解釋,那麽這個報錯也就不難看懂了。我們試圖將一串Bytes插入到一列中,而這串Bytes的第一個字節是\xF0意味著這是一個四字節的UTF-8編碼。但是當MySQL表和列字符集配置為UTF-8的時候是無法存儲這樣的字符的,所以報了錯。

【附】手持兩把錕斤拷, 口中疾呼燙燙燙。 腳踏千朵屯屯屯, 笑看萬物鍩鍩鍩。

從python2,python3編碼問題引伸出的通用編碼原理解釋