繼續收集python3編碼問題相關資料 資料來源 鵬程的新浪博客(轉載)http://blog.sina.com.cn/s/blog_6d7cf9e50102vo90.html 這篇鵬程老師寫的關於python3的編碼的博客寫的特別的清楚,直接就摘入下來。供自己作為參考。 1.從位元組說起: 一個位元組 ...
繼續收集python3編碼問題相關資料
資料來源 鵬程的新浪博客(轉載)http://blog.sina.com.cn/s/blog_6d7cf9e50102vo90.html 這篇鵬程老師寫的關於python3的編碼的博客寫的特別的清楚,直接就摘入下來。供自己作為參考。
1.從位元組說起:
一個位元組包括八個比特位,每個比特位表示0或1,一個位元組即可表示從00000000到11111111共2^8=256個數字。一個ASCII編碼使用一個位元組(除去位元組的最高位作為作奇偶校驗位),ASCII編碼實際使用一個位元組中的7個比特位來表示字元,共可表示2^7=128個字元。比如ASCII編碼中的01000001(即十進位的65)表示字元'A',01000001加上32之後的01100001(即十進位的97)表示字元'a'。現在打開Python,調用chr和ord函數,我們可以看到Python為我們對ASCII編碼進行了轉換。如圖
第一個00000000表示空字元,因此ASCII編碼實際上只包括了 字母、標點符號、特殊符號等共127個字元。因為ASCII是在美國出生的,對於由字母組成單詞進而用單詞表達的英文來說也是夠了。但是中國人、日本人、 南韓人等其他語言的人不服了。中文是一個字一個字,ASCII編碼用上了渾身解數256個字元都不夠用。
因此後來出現了Unicode編碼。Unicode編碼通常由兩個位元組組成,共表示256*256個字元,即所謂的UCS-2。某些偏僻字還會用到四個位元組,即所謂的UCS-4。也就是說Unicode標準也還在發展。但UCS-4出現的比較少,我們先記住:最原始的ASCII編碼使用一個位元組編碼,但由於語言差異字元眾多,人們用上了兩個位元組,出現了統一的、囊括多國語言的Unicode編碼。
在Unicode中,原本ASCII中的127個字元只需在前面補一個全零的位元組即可,比如前文談到的字元‘a’:01100001,在Unicode中變成了00000000 01100001。不久,美國人不開心了,吃上了世界民族之林的大鍋飯,原本只需一個位元組就能傳輸的英文現在變成兩個位元組,非常浪費存儲空間和傳輸速度。
人們再發揮聰明才智,於是出現了UTF-8編碼。因為針對的是空間浪費問題,因此這種UTF-8編碼是可變長短的,從英文字母的一個位元組,到中文的通常的三個位元組,再到某些生僻字的六個位元組。解決了空間問題,UTF-8編碼還有一個神奇的附加功能,那就是相容了老大哥的ASCII編碼。一些老古董軟體現在在UTF-8編碼中可以繼續工作。
註意除了英文字母相同,漢字在Unicode編碼和UTF-8編碼中通常是不同的。比如漢字的‘中’字在Unicode中是01001110 00101101,而在UTF-8編碼中是11100100 10111000 10101101。
我們祖國母親自然也有自己的一套標準。那就是GB2312和GBK。當然現在挺少看到。通常都是直接使用UTF-8。
2.Python3中的預設編碼
Python3中預設是UTF-8,我們通過以下代碼:
import sys
sys.getdefaultencoding()
可查看Python3的預設編碼。
3.Python3中的encode和decode
Python3中字元編碼經常會使用到decode和encode函數。特別是在抓取網頁中,這兩個函數用的熟練非常有好處。encode的作用,使我們看到的直觀的字元轉換成電腦內的位元組形式。decode剛好相反,把位元組形式的字元轉換成我們看的懂的、直觀的、“人模人樣”的形式。
\x表示後面是十六進位,\xe4\xb8\xad即是二進位的11100100 10111000 10101101。也就是說漢字‘中’encode成位元組形式,是11100100 10111000 10101101。同理,我們拿11100100 10111000 10101101也就是\xe4\xb8\xad來decode回來,就是漢字‘中’。完整的應該是b'\xe4\xb8\xad',在Python3中,以位元組形式表示的字元串則必須加上首碼b,也就是寫成上文的b'xxxx'形式。
前文說的Python3的預設編碼是UTF-8,所以我們可以看到,Python處理這些字元的時候是以UTF-8來處理的。因此從上圖可以看到,就算我們通過encode('utf-8')特意把字元encode為UTF-8編碼,出來的結果還是相同:b'\xe4\xb8\xad'。
明白了這一點,同時我們知道UTF-8相容ASCII,我們可以猜想大學時經常背誦的‘A’對應ASCII中的65,在這裡是不是也能正確的decode出來呢。十進位的65轉換成十六進位是41,我們嘗試下:
b'\x41'.decode()
結果如下。果然是字元‘A’
4.Python3中的編碼轉換
據說字元在電腦的記憶體中統一是以Unicode編碼的。只有在字元要被寫進文件、存進硬碟或者從伺服器發送至客戶端(例如網頁前端的代碼)時會變成utf-8。但其實我比較關心怎麼把這些字元以Unicode的位元組形式表現出來,露出它在記憶體中的廬山正面目的。這裡有個照妖鏡:
xxxx.encode/decode('unicode-escape')
b'\\u4e2d'還是b'\u4e2d,一個斜杠貌似沒影響。同時可以發現在shell視窗中,直接輸'\u4e2d'和輸入b'\u4e2d'.decode('unicode-escape')是相同的,都會列印出漢字‘中’,反而是'\u4e2d'.decode('unicode-escape')會報錯。說明說明Python3不僅支持Unicode,而且一個‘\uxxxx’格式的Unicode字元可被辨識且被等價於str類型。