Python3對文本(str)和二進制數據(bytes)作了更為清晰的區分。
文本默認是以Unicode編碼(python2默認是ascii),由str類型表示,二進制數據則由bytes類型表示。
str='中文ENGLISH'
str是文本類型,即str類型
>>> str.encode('utf-8') b'\xe4\xb8\xad\xe6\x96\x87ENGLISH' >>> str.encode('gb2312') b'\xd6\xd0\xce\xc4ENGLISH' >>> bytes(str,'utf-8') b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'
bytes()函數同str.encode(),即把str類型編碼為bytes類型
>>> b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'.decode('utf-8') '中文ENGLISH'
解碼過程,即把bytes數據轉化為str
>>> b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'.encode('utf-8') Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'.encode('utf-8') AttributeError: 'bytes' object has no attribute 'encode'
不能把bytes數據繼續編碼為bytes
>>> '中文ENGLISH'.decode('utf-8') Traceback (most recent call last): File "<pyshell#44>", line 1, in <module> '中文ENGLISH'.decode('utf-8') AttributeError: 'str' object has no attribute 'decode'
也不能把str數據繼續解碼為str
即編碼過程是從str到bytes,解碼過程是從bytes到str。
>>> b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'.decode('gb2312') Traceback (most recent call last): File "<pyshell#45>", line 1, in <module> b'\xe4\xb8\xad\xe6\x96\x87ENGLISH'.decode('gb2312') UnicodeDecodeError: 'gb2312' codec can't decode byte 0xad in position 2: illegal multibyte sequence
上面是把以utf-8編碼的bytes以gb2312的方式解碼,結果出錯了,因為0xad沒有對應的gb2312編碼
如果想知道一串bytes碼是以何種unicode編碼方式編碼的,該如何呢?這個其實是無法百分之百確定的,不然的話亂碼就不會發生了。
第三方庫chardet,使用函數detect可以“猜”出編碼方式。
from chardet import detect
>>> detect(b'\xe4\xb8\xad\xe6\x96\x87ENGLISH') {'confidence': 0.7525, 'encoding': 'utf-8'}
這里置信0.7525,可以簡單理解為概率0.7525,這里只有兩個中文字符,如果bytes足夠長,那么置信肯定更高
>>> detect(b'\xe6\x88\x91\xe6\x98\xaf\xe4\xb8\xad\xe6\x96\x87\xe6\x88\x91\xe7\x9c\x9f\xe7\x9a\x84\xe6\x98\xaf\xe4\xb8\xad\xe6\x96\x87') {'confidence': 0.99, 'encoding': 'utf-8'}
這里有10個中文字符,結果置信就是0.99了
__________________________________________________________________________________
從txt文件讀取的問題
有兩個文件ansi.txt和utf8.txt,分別保存為ansi編碼和utf-8編碼,里面都是‘中文ENGLISH’
>>> f_ansi=open(r'd:\ansi.txt','r') >>> f_ansi.read() '中文ENGLISH'
>>> f_utf8=open(r'd:\utf8.txt','r') >>> f_utf8.read() '鍩誇腑鏂嘐NGLISH'
>>> f_utf8=open(r'd:\utf8.txt','r',encoding='utf-8') >>> f_utf8.read() '\ufeff中文ENGLISH'
#帶BOM的utf8
記事本的ansi編碼為系統本地編碼,我的是gbk,所以ansi.txt的編碼方式是gbk
open()函數的encoding參數默認是本地編碼,也就是gbk,所以直接打開讀取ansi.txt是可以的
直接打開utf8編碼的txt會以gbk的解碼方式讀取,所以會出現亂碼
驗證一下
>>> '鍩誇腑鏂嘐NGLISH'.encode('gbk').decode('utf-8') '\ufeff中文ENGLISH'