1. 程式人生 > >編碼的秘密(python版)

編碼的秘密(python版)

默認 字節數 二進制格式 type eight 符號 占用 終端 自己

編碼(python版)

最近在學習python的過程中,被不同的編碼搞得有點暈,於是看了前人的留下的文檔,加上自己的理解,準備寫下來,分享給正在為編碼苦苦了掙紮的你。

編碼的概念

編碼就是將信息從一種格式轉換成另一種格式,計算機只認識二進制,簡單的理解,將我們眼睛看到的文字轉換為計算機能夠識別的二進制格式視為編碼,而二進制以某種編碼格式轉換為我們能看的文字的過程可以看成是解碼。既然計算機只能認識二進制0,1,那麽我們用的字母、數字和文字等是怎樣和他們對應的呢?那就請繼續看吧!

python中查看默認的編碼規範是:

import sys
print(sys.getdefaultencoding())

#運行結果: C:\python35\python35.exe E:/py_fullstack/字符編碼2.py utf-8

ASCⅡ碼

我們都知道計算機是米國發明的,起初的時候也只有米國那些國家使用,而他們的語言僅僅只有26個字母組成,再加上一些符號,所以在一開始的時候,用的編碼規則就是ASCⅡ碼。ASCⅡ,中文名叫美國信息交換標準代碼,因為名叫American Standard Code for Information Interchange,下面我們來看看ASCⅡ表:

技術分享

ASCⅡ碼用一個字節,也就是8位二進制組來標識一個字符,比如00100001就代表字符!,第一版的ASCⅡ沒有用到最高的一個bit,所以取值範圍為0-127,只能表示128字符。為了滿足西歐等國家的字符要求,於是用上了最高位的bit,能表示的字符也從128增加到了256個。

技術分享

在python中使用函數ord(),可以字符轉換為對應數值,使用函數chr可以將數值轉換為對應字符:

>>> ord("a")     #將字符轉換為數值
97
>>> ord("A")
65
>>> chr(65)
A
>>> chr(97)      #將數值轉換為字符
a
>>>

GB2312和GBK

當計算機漂洋過海來到了中國,ASCⅡ已經不能滿足我大天朝的需求了,常用的漢字大致都有2k-3k。所以中國國家標準總局在1980發布了《信息交換用漢字編碼字符集》,也就是GB2313標準。GB2312一共收錄了7445個字符(6763個漢字和682個其他符號),包括拉丁字母、希臘字母和日文平假名等,基本上滿足了國人的需求。

在GB2312中每個漢字使用兩個字節來表示,分為高字節和低字節,漢字區高字節從B0-F7,低字節從A1-FE,占用的碼位是72*94=6768,其中有5個空位是D7FA-D7FE,規定第一個字節大於127的就代表這是一個漢字的開始(這一個字節和下一個字節就代表一個漢字),每個字節的最高位都位1。

但是對於人名、古漢語等方面出現的罕用字,GB2312不能處理,後來就出現了GBK。GBK向下兼容GB2312,其編碼範圍從8140到FEFE(不包括xx7F),共23940個碼位,共收錄了21003個漢字,這還是很厲害的了。現在我們使用的計算機默認的就是GBK編碼。

技術分享

Unicode和UTF-8

我們國家搞出了GBK,其他的國家也搞出了各種各樣的編碼,比如小日本的SJIJ,寶島臺灣的BIG5,國際組織一看,這不行啊,每個地方都各自搞各自的,那麽在不同的國家之間就會出現不兼容,我用GBK編碼格式寫的軟件,弄到你編碼格式為SJIJ的計算機就不能執行了。所以就出現了Unicode,也稱萬國碼。unicode是用2個字節來表示一個字符的,65536類個字符,這足以覆蓋世界上所有的文字。

這樣雖好,但是美國人民就不開心了,我一個字母,比如‘a‘就需要占用一個字節,現在需要占用兩個字節,這樣就大大的浪費了內存和硬盤的空間,所有後來就出現了UTF-32,UTF-16和UTF-8,前兩個這裏就不在敖述了,現在並不常用,我們這看看這個UTF-8,UTF-8是一種可變長的編碼格式,存儲英文字母只需要一個字節,存儲漢字需要3個字節,但超大字符集中的更大多數漢字要占4個字節。我們在內存裏面的數據是unicode,在傳輸數據和保存數據的時候適用UTF-8已節省空間和帶寬。

Python2的編碼

在python2中默認的編碼是ASCII,python2的字符串類型有兩種:str和Unicode,這兩個只是字符串類型的名字,我們主要看它們在內存裏面的內存地址:

#coding=utf8

name = 彬彬
name2 = u彬彬   #加u,將字符串類型改為Unicode
print  repr(name)
print  repr(name2)

#輸出結果

C:\Python27\python.exe E:/py_fullstack/字符編碼.py
‘\xe5\xbd\xac\xe5\xbd\xac‘ #字節數據
u‘\u5f6c\u5f6c‘ #Unicode數據

技術分享

在python2中,str類型字符串類型在內存中存儲的是bytes數據,Unicode類型字符串在內存中存儲的是unicode數據。那兩種數據之間是什麽關系了?這裏就涉及到了解碼(encode)和編碼(decode)了。

#coding=utf8

name = 彬彬                #name為字節數據類型
name2 = u彬彬            #name為unicode數據類型
print  repr(name)         
print repr(name2)
name3 = name.decode(utf8)  
print type(name3)
print repr(name3)
name4 = name2.encode(utf8)
print type(name4)
print repr(name4)

#運行結果
C:\Python27\python.exe E:/py_fullstack/字符編碼.py
\xe5\xbd\xac\xe5\xbd\xac
u\u5f6c\u5f6c
<type unicode>
u\u5f6c\u5f6c
<type str>
\xe5\xbd\xac\xe5\xbd\xac

由上運行結果可知,unicode轉換為bytes數據的過程是編碼。從bytes數據轉換為unicode數據的過程是解碼。我們再來看一下:

#coding=utf8
name = 彬彬
name3 = name.decode(big5)
print name3

#運行結果
C:\Python27\python.exe E:/py_fullstack/字符編碼.py
敶砍蓮

我們可以看到得到一堆亂文,name存在內存裏的時候是以UTF編碼成的bytes數據,而我們這裏decode(‘big5‘)使用big5來解碼,雖然成功了,但是輸出結果卻不是我們想要的結果。

當我們把第一行coding改為big5的時候就不會出現亂文了,

#coding=big5
name = 彬彬
name3 = name.decode(big5)
print name3

#運行結果
C:\Python27\python.exe E:/py_fullstack/字符編碼.py
彬彬

所以我們用什麽規則編碼的就要用什麽區解碼!

技術分享

註意:我們在終端顯示出來的明文,就是你用戶所看到的,其實都是已經轉換成unicode到內存裏面,而bytes數據一般都是計算機識別的。

Python3的編碼

在Python3中也定義了2種類型的字符串類型,str和bytes,str類型存儲unicode數據,bytes類型存儲bytes數據。

技術分享

name = "彬彬"
name2 = b"hello"
print(type(name))
print(type(name.encode(utf8)))
print(type(name.encode(gbk)))
print(type(name2))
print(type(name2.decode(utf8)))

#運行結果
<class str>
<class bytes>
<class bytes>
<class bytes>
<class str>

如上運行結果,bytes轉換為unicode為解碼,uicode轉為bytes數據類型為編碼。

技術分享

由上圖所示,在不同的編碼之間轉換的時候,我們都要經過unicode這個中轉站,沒辦法,雖然unicode老大哥強大呢,當我們想把utf-8編碼的數據轉換為gbk的,我們就需要把utf-8的數據先解碼成unicode,再由unicode編碼成gbk。

在py2和py3中有個重要的區分就是,py2會自動把bytes數據解碼成unicode,而py3就不會自動把bytes解碼成unicode了。所以說py3更清晰的區分了bytes數據和unicode。

#py2中
print(u"liu" + "bin")

#運行結果
C:\Python27\python.exe E:/py_fullstack/字符編碼2.py
liubin
#py3中
print("liu" + b"bin")
#運行結果
Traceback (most recent call last):
  File "E:/py_fullstack/字符編碼2.py", line 2, in <module>
    print("liu" + b"bin")
TypeError: Cant convert bytes object to str implicitly
print("liu" + (b"bin").decode(‘utf8‘))

#運行結果

C:\python35\python35.exe E:/py_fullstack/字符編碼2.py
liubin

一個.py文件的"一生"

那我們創建.py文件,到執行.py文件,這裏面的編碼和解碼是怎麽來的呢?

1.當我們創建一個.py文件的時候,會有一個默認的編碼格式(這裏以pycharm為例),在右下角,默認是UTF-8,當然你也可以選擇其他的編碼:

技術分享

2.當我們在.py文件裏面寫入代碼的時候,會以unicode的編碼格式保存在內存中;

技術分享

3.當我們保存的時候,會將Unicode數據編碼成utf-8格式的數據,然後保存在硬盤裏面;

4.當我們執行文件的時候,pycharm會調用python的解釋器來讀取文件,在py2中,默認會以ASCII將代碼解碼成unicode數據,但是ASCII碼並不認識中文,所以就會出現報錯。

技術分享

所以,在py2中,我們需要加上:

#coding=utf8
print("你好,世界!")

#運行結果
C:\Python27\python.exe E:/py_fullstack/字符編碼.py
你好,世界!

但是在py3中就不存在這個問題了,只要編碼的時候適用的是UTF-8,python3默認的編碼規範就是UTF-8,它會用UTF-8來將UTF-8的bytes數據解碼成unicode,然後在計算機終端顯示!

編碼的秘密(python版)