本節我們接着講bytes類型,上一節內容:
免費視頻教程!零基礎學Python系列(7) - 數據類型之bytes(上)
本節課程的視頻和實例源碼下載方式:點擊->我的主頁,查看個人簡介。
我儘量堅持每日更新一節。
-
字符編碼
Python2.x的亂碼問題一直被程序員所詬病,雖然Python3.X大體上已經解決了這個問題,但是作爲入門python的基礎,你還是需要把字符編碼問題搞得非常清楚,否則你會被各種“亂碼”搞崩潰。下面是引用的知乎上面一個回答,挺有意思:
- 什麼是字符編碼呢?
我們知道計算機是使用01這樣的二進制串來存儲數據的,這裏的數據不僅僅是數字,而是所有數據,包括圖片、視頻、音頻、文字等等。所以,我們需要有一個規則,來定義這些數據和二進制之間如何轉換。
字符編碼,就是一套標準(事實上有若干套標準),根據這些標準,我們將字符和二進制雙向轉換。
最早的字符編碼標準,叫做ASCII碼。
- ASCII碼
計算機技術起源於美國,所以最早的字符編碼標準ASCII(American Standard Code for Information Interchange)也是老美根據他們的語言體系制定的。在英語的世界裏面,26個小寫字母、26個大寫字母、若干個標點符號、一些控制符號等就可以表示所有字符。
下面就是全部的ASCII編碼,一共就只有256個符號的編碼定義:
第一列是字符對應的十進制數值,比如001d;
第二列是字符對應的十六進制數值,比如0Ah;
第三列是對應的字符;
0~31還定義了第四列,用於表示一些特殊的控制符,比如008d對應的是退格(Backspace),我們敲鍵盤的Backspace退格鍵,就會產生008d這個數值在計算機中傳遞。
最早 ASCII 只定義了128個字符編碼,包括96個顯示字符和32個控制符號,一共128個字符,只佔用了一個字節8bit位中的低7位。然而隨着計算機慢慢普及,一些西歐字符在字符集中無法被表示,於是就有了下面那種擴展ASCII表,將字符集擴展到了256個。
- GB2312\GBK
ASCII碼標準的指定可沒有考慮中文的問題,於是當計算機在中國以及亞洲國家出現以後,中文編碼成了一個問題。爲了解決這個問題,我國制定了自己的字符編碼標準GB2312(GB-國標)。GB2312收錄的漢字基本覆蓋了我們使用的絕大多數場景,但是對於繁體字和少數民族文字無法處理。於是後來又制定了GBK標準(K-擴展),GBK在GB2312基礎上制定,它除了收錄27484個漢字以外,還收錄了藏文、蒙文、維吾爾文等少數民族文字。
GBK採用兩個字節來表示中文,同時它也兼容ASCII標準,當使用ASCII字符時可以自動轉換爲一個字節來表示。
- Unicode
不同國家都有自己的語言和文字,如果大家都自己制定自己的字符編碼規範,那它們之間如何互通呢?爲了解決這個問題,科學家們發明一種統一的字符編碼-unicode(UniversalMultiple-OctetCodedCharacterSet,簡稱UCS),它幾乎囊括了人類所有語系字符的編碼。Unicode同樣也是兼容ascii碼的。
Unicode採用2字節編碼,這一標準的2字節形式叫做UCS-2。但是我們知道2字節最多隻能表示65535個字符編碼,這對於一些特殊語系來說是完全不夠的,比如中文字符就有幾萬個。所以,unicode還有一種4字節的形式,叫做UCS-4,它有足夠的空間可以定義人類所有的文字符號。
- UTF-8
Unicode是一個字符集,它僅定義了不同符號對應的編碼值。但是這個字符該如何存儲呢?對於ascii碼,我們可以統一採用一個字節來存儲不同的字符。Unicode字符也可以這樣操作,但這樣會帶來一個存儲效率的問題。
比如字符“a”,它對應的編碼是61,一個字節就可以表示。如果我們採用4字節表示,那麼有3個字節就浪費掉了。在英語系國家,這種浪費就顯得非常嚴重,接近3/4的存儲性能損失,這是不能被接受的。
基於這個原因,出現了各種unicode的實現方法,最著名的是UTF-8。
UTF-8以一個字節(8比特位)爲一個編碼單位,並且它是變長的。對於不同的unicode字符,它會採用不同的字節長度來存儲。這樣就可以大大提升存儲性能。
比如漢字“中”,它的unicode表示和utf-8編碼如下:
除了UTF-8,還有UTF-16,同理,它是以16比特-2字節爲一個編碼單位。
字符亂碼的原因,基本都是字符編碼不一致導致的。Python2默認採用ascii碼,中文字符默認是不能轉換的,所以我們在python2代碼中如果涉及中文字符,必須在代碼文件一開始就進行字符編碼的聲明:
# -*-coding:utf-8-*-
Python2的字符編碼問題備受詬病。在python3中,默認編碼改成了utf-8,所以我們不聲明編碼類型,也是可以正常支持中文字符的。
字符編碼需要端到端保持一致,不管是存儲、計算、傳輸等環節都要設置一致,比如我們代碼處理時採用的字符編碼必須和數據庫存儲的編碼方式一致。否則很容易出現亂碼。
-
Bytes和string之間的轉換
Bytes和string之間的轉換,其本質就是一個字符編碼的過程。Python3提供了encode和decode方式來實現兩者之間的靈活轉換,其過程如下圖:
Encode是字符編碼過程,將字符轉換爲指定的編碼,並以bytes類型存儲;
Decode則相反,將bytes值轉換爲對應的字符。
語法如下:
str.encode(encoding='UTF-8',errors='strict')
str.decode(encoding='UTF-8',errors='strict')
encoding -- 要使用的編碼方式,如"UTF-8"。
errors -- 設置不同錯誤的處理方案。默認爲 'strict',意爲編碼錯誤引起一個UnicodeError。 其他可能得值有 'ignore', 'replace', 'xmlcharrefreplace', 'backslashreplace' 以及通過 codecs.register_error() 註冊的任何值。
下面是一個編解碼的例子:
# author: Tiger, wx ID:tiger-python
# file: ./6/6_3.py
# bytes 按照16進制輸出,強制不ascii轉碼
def trans(s):
return "b'%s'" % ''.join('\\x%.2x' % x for x in s)
# 字符編碼
encstr_1 = 'tiger-python'
encbytes_1 = encstr_1.encode('utf-8')
print(trans(encbytes_1))
print(encbytes_1.decode('utf-16')) # 編碼方式不一致,造成亂碼
print(encbytes_1.decode('utf-8'))
輸出爲:
b'\x74\x69\x67\x65\x72\x2d\x70\x79\x74\x68\x6f\x6e'
楴敧祰桴湯
tiger-python
如果編解碼的編碼方式不一致,則出現亂碼。
好了,下節我們繼續學習python的其它數據類型。
本節課程的視頻和實例源碼下載方式:點擊->我的主頁,查看個人簡介。
我儘量堅持每日更新一節。