1. 程式人生 > 其它 >Python encode 與 decode 深入理解

Python encode 與 decode 深入理解

前言

在理解encode和decode之前,必須先知道以下幾個概念:

  • ascii、gb2312、gbk、gb18030、utf8、unicode:上面這些均是字元編碼規範;其中gb2312、gbk、gb18030是我國出的規範,其他的是外國人出的規範;
    例如‘姜’字,用gbk、utf8或unicode編碼(encode操作),在記憶體中佔的位元組是不一樣的,所以檔案出現亂碼,是檔案開啟時使用的編碼格式不對。
  • str和bytes是字串型別,是程式語言的基本資料型別、和int、dict、list是一個級別的。

encode()

encode() 方法為字串型別(str)提供的方法,用於將 str 型別轉換成 bytes 型別,這個過程也稱為“編碼”。
encode() 方法的語法格式如下:


str.encode([encoding="utf-8"][,errors="strict"])

# [] 中表示是可選引數

# encoding = "utf-8" 
# 指定進行編碼時採用的字元編碼,該選項預設採用 utf-8 編碼。例如,如果想使用簡體中文,可以設定 gb2312。
# 當方法中只使用這一個引數時,可以省略前邊的“encoding=”,直接寫編碼格式,例如 str.encode("UTF-8")。

# errors = "strict"
# 指定錯誤處理方式,其可選擇值可以是:
# - strict:遇到非法字元就丟擲異常。
# - ignore:忽略非法字元。
# - replace:用“?”替換非法字元。
# - xmlcharrefreplace:使用 xml 的字元引用。
# 該引數的預設值為 strict。

decode()

和 encode() 方法正好相反,decode() 方法用於將 bytes 型別的二進位制資料轉換為 str 型別,這個過程也稱為“解碼”。
decode() 方法的語法格式如下:


bytes.decode([encoding="utf-8"][,errors="strict"])

# [] 中表示是可選引數

# encoding="utf-8"
# 指定解碼時採用的字元編碼,預設採用 utf-8 格式。當方法中只使用這一個引數時,可以省略“encoding=”,直接寫編碼方式即可。
# 注意,對 bytes 型別資料解碼,要選擇和當初編碼時一樣的格式。

# errors = "strict"
# 用法同 encode()

其他

1、 encoding 的可選值 參考《官方文件》,常用的選項有ascii、gb2312、gbk、gb18030、utf_8、utf_8_sig、unicode_escape
2、 encoding='utf_8'encoding='utf8'encoding='utf-8',這三種寫法是一樣的
3、 個人理解見下:

>>> s = "C語言中文網"
>>> s.encode()
b'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'
>>> s.encode().decode()
C語言中文網

上面示例中,'C語言中文網'.encode()之後的打印出來為b'xxx'格式,是因為encode()之後資料為bytes型別,bytes型別資料在控制檯的表現形式就是以b''開頭的。
至於'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91',是一堆二進位制資料的表示形式,
由ascii字元+16進位制數字組成,一個ascii字元或一個16進位制數字代表一個位元組,例如,'C'表示一個位元組,\xe8表示另一個位元組(\x表示16進位制的意思),
utf8編碼中,字母、數字、常用符號的編碼同ascii編碼是一樣的,佔一個位元組;漢字的編碼是用三個位元組表示的,
所以,'C'在utf8編碼中對應'\x43','語'在utf8編碼中對應是'\xe8\xaf\xad',其他字元以次類推,就得到了'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91',這個過程就是編碼,也就是encode()。
注意的是:'C'打印出來是'C',而不是'\x43',只是列印時為了區分一個位元組utf8和3個位元組的utf8,直接使用\x43是一樣的效果,均可以正常解碼。

例如:

>>> b'\x43\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'.decode() 
'C語言中文網'
>>> b'C\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'.decode()    
'C語言中文網'
>>> 

如果不知道編碼情況下,單獨看一個位元組是沒意義的;例如,'\xe8'的16進位制是e8,10進位制是232,2進位制是11101000,僅僅是一個數字。
但是,如果知道是utf8編碼時,就對這些數字賦予了意義,例如'\xe8\xaf\xad'是三個位元組,在utf8編碼中對應的是漢字‘語’;
從b'\xe8\xaf\xad'轉換成‘語’的過程就是編碼,也就是decode()。

問題1:b'\x43\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91' utf8解碼的過程中,怎麼知道該取一個位元組解碼還是取3個字元解碼?

一個位元組的utf8,一定是在\x01\x7f之間,翻譯成10進位制就是1127;反過來講就是,在\x01~\x7f之間位元組,是一定表示一個位元組的utf8;
三個位元組的utf8中每一個位元組,一定是在\x80\xff之間,翻譯成10進位制就是128255。反過來講就是, 在\x80~\xff之間的位元組,是一定表示3個位元組的utf8;
所以在解碼的過程中,取每一個位元組時會判斷區間,然後就知道解碼成一個一位元組還是三個位元組了

問題2:我有一堆'\x43\xe8\xaf\xad\xe8\xa8\x80\xe4\xb8\xad\xe6\x96\x87\xe7\xbd\x91'的資料,怎麼能正常顯示出來?

第一步,先把這堆str按原二進位制位轉成bytes型別

s = 'C\xd3\xef\xd1\xd4\xd6\xd0\xce\xc4\xcd\xf8'    # 注意s是str型別,非bytes
>>> s.encode('raw_unicode_escape') 
b'C\xd3\xef\xd1\xd4\xd6\xd0\xce\xc4\xcd\xf8'        

第二步,嘗試用各種編碼規則解碼,如果能正常解析,就知道了這堆字串的正確編碼

>>> s.encode('raw_unicode_escape').decode('utf8')  
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xd3 in position 1: invalid continuation byte
>>> s.encode('raw_unicode_escape').decode('gb2312') 
'C語言中文網'
>>> s.encode('raw_unicode_escape').decode('gbk')    
'C語言中文網'
>>> s.encode('raw_unicode_escape').decode('gb18030') 
'C語言中文網'

參考:http://c.biancheng.net/view/4305.html