Python的解碼與編碼

一、字符與編碼的關係

在學習之前,我們學習幾個概念,讓我們達成一個共識。理論上,從一個字符到具體的編碼,會經過以下幾個概念。
字符集(Abstract character repertoire)
編碼字符集(Coded character set)
字符編碼方式(Character encoding form)
字符編碼方案(Character encoding scheme )

字符集:也就是我們肉眼能識別的文字,如中文、英語、德語。

編碼字符集:是一個從整數集子集到字符集抽象元素的映射,即給抽象的字符編上數字
如 Unicode 中的定義的字符,每個字符都有個數字和它對應,一隻對應着一個字符。
反過來,則不一定是。這裏所說的映射關係,是數學意義上的映射關係。
編碼字符集也是與計算機無關的,ASCII、UTF、Unicode、GBK等字符集也在這一層。
如漢字“中文”的Unicode的編碼是:\u4e2d\u6587;utf-8編碼爲 b'\xe4\xb8\xad\xe5\x9b\xbd',GBK的編碼爲:b'\xd6\xd0\xb9\xfa'

字符編碼方式:這個開始與計算機有關了,編碼字符集的編碼點在計算機裏的具體表現形式
通俗的說,意思就是怎麼樣才能將字符所對應的整數的放進計算機內存、或文件、或網絡中。
於是,不同人有不同的實現方式,所謂的萬碼奔騰,就是指這個;GB2312、UTF-8、UTF-16、UTF-32等都在這一層。
如漢字“中文”的Unicode編碼爲“\u4e2d\u6587”,他在計算機的存儲按十六進制展開爲:‭‭100 1110 0010 1101 0110 0101 1000 0111‬;

編碼方案:這個更加與計算機密切相關,具體是與操作系統密切相關,主要是解決大小字節序的問題。
對於UTF-16和UTF-32編碼,Unicode都支持big-endian 和 little-endian兩種編碼方案。


一般來說,我們所說的編碼、解碼,都在第二、三層完成,而序列化、反序列化在第一層。

二、編碼與解碼

爲了簡化理解,在Python3當中,只有兩種編碼,Unicode與 bytes,而Unicode=str,他們的轉換關係:

str-->str.encode('字符編碼') -->bytes -->bytes.decode('字符編碼') --> str

編碼(encode)就是將字符串(str)轉換成字節碼(bytes);
解碼(decode)就是將字節碼(bytes)轉換爲字符串(str);

舉個栗子:

oath = '中文'
utf8 = oath.encode('utf-8')
oath1 = utf8.decode('utf-8')
print("對‘中文’按utf-8進行編碼:",utf8,',長度:',len(utf8),'類型:',type(utf8),'佔用字節:',sys.getsizeof(utf8))
print('對編碼過的變量進行解碼:',oath1,'長度:',len(oath1),'類型:',type(oath1),'佔用字節:',sys.getsizeof(oath1))

運行結果:

對‘中文’按utf-8進行編碼: b'\xe4\xb8\xad\xe6\x96\x87' ,長度: 6 類型: <class 'bytes'> 佔用字節: 39
對編碼過的變量進行解碼: 中文 長度: 2 類型: <class 'str'> 佔用字節: 78

證明str==Unicode

oath = '我愛妞'
print(oath,',長度:',len(oath),'類型:',type(oath),'佔用字節:',sys.getsizeof(oath))
oath1 = u'我愛妞'
print(oath1,',長度:',len(oath1),'類型:',type(oath1),'佔用字節:',sys.getsizeof(oath1))
print('oath==oath1:',oath==oath1,'所以,str實際存儲的是Unicode字符,那麼也可以Unicode編碼來存儲str')
我愛妞 ,長度: 3 類型: <class 'str'> 佔用字節: 80
我愛妞 ,長度: 3 類型: <class 'str'> 佔用字節: 80
oath==oath1: True 所以,str實際存儲的是Unicode字符,那麼也可以Unicode編碼來存儲str

另:

oath2='\u5220\u9664'
print(r'所以說這樣形式的Unicode字符:\u5220\u9664,可以直接顯示出正確的編碼:',oath2,type(oath2))
print('也可以編碼爲二進制字符:',oath2.encode(),type(oath2.encode()),'所以,字符串常量,前綴帶不帶u,都是一樣的')
print(r'再解碼b\xe5\x88\xa0\xe9\x99\xa4,爲:',oath2.encode().decode('utf-8'),type(oath2.encode().decode('utf-8')))
所以說這樣形式的Unicode字符:\u5220\u9664,可以直接顯示出正確的編碼: 刪除 <class 'str'>
也可以編碼爲二進制字符: b'\xe5\x88\xa0\xe9\x99\xa4' <class 'bytes'> 所以,字符串常量,前綴帶不帶u,都是一樣的
再解碼b\xe5\x88\xa0\xe9\x99\xa4,爲: 刪除 <class 'str'>

接下來我們來看一個例子(運行環境:Python3):

b'\xc0\xeb\xc0\xeb\xd4\xad\xc9\xcf\xb2\xdd\xa3\xac\xd2\xbb\xcb\xea\xd2\xbb\xbf\xdd\xc8\xd9'

上面這一串二進制字符是我們從某個文件讀取到的字符串,我們需要知道它是什麼意思,怎麼辦呢?

這就需要我們對他進行解碼(decode)了,在解碼之前我們需要知道他是什麼類型的編碼,才能用對應的方式進行解碼,當然,你也可以一個一個的去試,但這不太程序員。

import chardet

data = b'\xc0\xeb\xc0\xeb\xd4\xad\xc9\xcf\xb2\xdd\xa3\xac\xd2\xbb\xcb\xea\xd2\xbb\xbf\xdd\xc8\xd9'
print(type('data'),'檢測這串bytes字符是什麼編碼:',chardet.detect(data))
#結果:<class 'str'> 這串bytes字符是什麼編碼: {'encoding': 'GB2312', 'confidence': 0.7407407407407407, 'language': 'Chinese'}
print('然後可以根據檢測出來的編碼進行解碼:',data.decode('GB2312'))
print('這也就解釋了用什麼方式編碼,就要用什麼方式解碼')
#print('當然你也可以試試用utf-8解碼,你就會發現他報錯:',data.decode('utf-8'))

運行結果:

<class 'str'> 檢測這串bytes字符是什麼編碼: {'encoding': 'GB2312', 'confidence': 0.7407407407407407, 'language': 'Chinese'}
然後可以根據檢測出來的編碼進行解碼: 離離原上草,一歲一枯榮
這也就解釋了用什麼方式編碼,就要用什麼方式解碼

參考原文:

https://blog.csdn.net/qq_38607035/article/details/82591931

python編碼轉換 以及轉換成unicode報錯的問題
https://www.cnblogs.com/reyinever/p/7931811.html
 
 python 查看當前字符串的編碼格式
https://blog.csdn.net/sinat_24648637/article/details/84190482

https://www.zhihu.com/question/31833164

Python2 與 Python3 的編碼對比
http://kuanghy.github.io/2016/10/15/encoding-python2-vs-python3

python3 三種字符串(無前綴,前綴u,前綴b)與encode()
https://blog.csdn.net/anlian523/article/details/80504699

廖雪峯的官網 字符串和編碼
https://www.liaoxuefeng.com/wiki/1016959663602400/1017075323632896
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章