標籤:ash height 簡單 解釋 開頭 聲明 mysql資料庫 就會 數字
今天使用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 1 |
Byte 2 |
Byte3 |
| 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十六進位編碼一定是以
C或D開頭的
- 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編碼問題引伸出的通用編碼原理解釋