【Python】文本編碼與chardet模塊

簡介

以前一直對字符編碼很模糊,感覺編碼方式有很多,在網(wǎng)上查資料也總是看的暈頭轉(zhuǎn)向,所以在這里先將幾種常見的編碼方式的關(guān)系總結(jié)一下。
常見的字符編碼——ASCII、UnicodeGBK、UTF-8

  • ASCII

ASCII編碼的全稱是American Standard Code for Information Interchange,美國信息互換標(biāo)準(zhǔn)代碼。這是一種最早的、只用來保存英文文字的編碼方式。ASCII編碼方式只使用了1個(gè)字節(jié)(8比特位,可以組合出256種不同的狀態(tài))中0~127種組合存儲了英文的文字。

  • GBK

當(dāng)計(jì)算機(jī)普及到國內(nèi)時(shí),因?yàn)闈h字的常用字就有將近6000個(gè),使用ASCII編碼已經(jīng)完全不能滿足使用的需求了。
所以在1981年,國家標(biāo)準(zhǔn)總局發(fā)布了GB2312(中國國家標(biāo)準(zhǔn)簡體中文字符集),使用2個(gè)字節(jié)的組合,當(dāng)兩個(gè)大于127的字符連在一起時(shí),就表示一個(gè)漢字,這樣就組合出了7000多個(gè)簡體字。
后來因?yàn)闈h字的擴(kuò)展需求,發(fā)布了GBK標(biāo)準(zhǔn),K是擴(kuò)展一次漢語拼音的聲母。即不再要求第二個(gè)字節(jié)大于127,只要第一個(gè)字節(jié)大于127,則表示這是一個(gè)漢字的開始。這樣共收錄了將近22000個(gè)漢字和符號。且兼容了GB2312標(biāo)準(zhǔn)。
2005年時(shí)修訂了GB18030標(biāo)準(zhǔn),支持了國內(nèi)少數(shù)民族的文字,共收錄漢字70000余個(gè)。兼容了GBK標(biāo)準(zhǔn)。

  • Unicode

就如國內(nèi)定義了GB2312標(biāo)準(zhǔn)一樣,當(dāng)時(shí)各個(gè)國家都規(guī)定了適用于自己語言的一套編碼方式。但是這就導(dǎo)致各國相互之間誰也不懂誰的編碼,裝錯(cuò)字符系統(tǒng)就會導(dǎo)致顯示全是亂碼。
所以這時(shí)ISO(International Standards Organization,國際標(biāo)準(zhǔn)化組織)推出了Unicode標(biāo)準(zhǔn)用以解決這個(gè)問題。
Unicode標(biāo)識以2個(gè)字節(jié)長度的數(shù)字來標(biāo)識所有字符,除了英文以外的字符全部重新進(jìn)行了統(tǒng)一編碼。
注意Unicode只是一種標(biāo)準(zhǔn),不是編碼方式,給予了每個(gè)字符一個(gè)16比特位的數(shù)字標(biāo)識,至于這個(gè)字符在內(nèi)存中是由幾個(gè)字節(jié)存儲,并不是Unicode標(biāo)準(zhǔn)規(guī)定的。

  • UTF-8

Unicode標(biāo)準(zhǔn)制定后,在很長的一段時(shí)間內(nèi)無法推廣,直到互聯(lián)網(wǎng)的普及,強(qiáng)烈要求出現(xiàn)一種統(tǒng)一的編碼方式。然后就誕生了UTF-8,這個(gè)使用Unicode標(biāo)準(zhǔn)的編碼方式。
注意:因此,UTF-8是Unicode標(biāo)準(zhǔn)的一種實(shí)現(xiàn)方式。

UTF-8的編碼規(guī)則很簡單,只有兩條:

  1. 對于單字節(jié)的符號,字節(jié)的第一位設(shè)為0,后面7位為這個(gè)符號的 Unicode 碼。因此對于英語字母,UTF-8 編碼和ASCII碼是相同的。
  2. 對于n字節(jié)的符號(n > 1),第一個(gè)字節(jié)的前n位都設(shè)為1,第n + 1位設(shè)為0,后面字節(jié)的前兩位一律設(shè)為10。剩下的沒有提及的二進(jìn)制位,全部為這個(gè)符號的 Unicode 碼。

下表為編碼規(guī)則,字母x表示可用編碼的位。

Unicode符號范圍 UTF-8編碼方式(二進(jìn)制)
0000 0000-0000 007F 0xxxxxxx
0000 0080-0000 07FF 110xxxxx 10xxxxxx
0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
0001 0000-0010 FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx


以漢字嚴(yán)為例,演示如何實(shí)現(xiàn)UTF-8編碼:

嚴(yán)的Unicode碼是4E25100111000100101),根據(jù)上表,可以發(fā)現(xiàn)4E25處在第三行的范圍內(nèi)(0000 0800 - 0000 FFFF),因此嚴(yán)的 UTF-8 編碼需要三個(gè)字節(jié),即格式是1110xxxx 10xxxxxx 10xxxxxx。然后,從嚴(yán)的最后一個(gè)二進(jìn)制位開始,依次從后向前填入格式中的x,多出的位補(bǔ)0。這樣就得到了,嚴(yán)的 UTF-8 編碼是11100100 10111000 10100101,轉(zhuǎn)換成十六進(jìn)制就是E4B8A5

由此可見,漢字的Unicode碼和UTF-8編碼是不同的,它們之間可以通過規(guī)則進(jìn)行轉(zhuǎn)換

注意 : 漢字的Unicode碼是2個(gè)字節(jié),而UTF-8碼是3個(gè)字節(jié)


Python 中的編碼方式轉(zhuǎn)換

Python3中的字符序列類型有兩種:strbytes

bytes對象是一串十六進(jìn)制格式字符序列,如b'\xe6\x88\x91',前方的b標(biāo)示這串字符是bytes對象。

將bytes對象通過上述的某種編碼方式可以解析為字符串,如將b'\xe6\x88\x91'使用UTF-8編碼方式解碼得到漢字,而使用GBK編碼方式解碼無法得到完整的漢字。

Python3中使用encode()decode()進(jìn)行字符與二進(jìn)制序列之間的轉(zhuǎn)換,可以這樣理解:
encode(編碼)就是把人能看懂的漢字,轉(zhuǎn)換為機(jī)器能看懂的二進(jìn)制序列。
decode(解碼)就是把人看不懂的二進(jìn)制序列,轉(zhuǎn)換為漢字。

使用encode()decode()時(shí),有個(gè)encoding參數(shù),默認(rèn)值為UTF-8,指定了對字符串進(jìn)行編碼或解碼時(shí),使用的編碼方式。


有關(guān)文件的編碼方式

前面說了那么多,還沒有講到有關(guān)文件的編碼方式,而且可能平時(shí)使用open()打開文件read()的時(shí)候,并沒有指定編碼方式,也能夠正常打印出來文件的內(nèi)容。

文件的編碼方式是在open()是指定的,有個(gè)encoding參數(shù),作用和字符串解碼一樣,如果以非二進(jìn)制模式(b)打開文件,會默認(rèn)通過UTF-8方式打開。

所以一份GBK編碼的文件,如果不以二進(jìn)制模式打開、且不設(shè)置這個(gè)encoding參數(shù),是會報(bào)解碼錯(cuò)誤的(UnicodeDecodeError)。

當(dāng)然,如果以二進(jìn)制模式打開文件,再讀取到的文本就已經(jīng)是二進(jìn)制序列了,不涉及encode問題,而是該以什么解碼方式將二進(jìn)制序列轉(zhuǎn)換為人可以讀懂的漢字。

所以對于一個(gè)未知編碼方式的文件,如何通過代碼獲取其編碼方式,然后轉(zhuǎn)換為我們所期望的編碼方式呢?
Python提供了一個(gè)第三方庫chardet,是char detect的縮寫,字符監(jiān)測。
將二進(jìn)制序列傳入chardet.detect()方法,然后會返回一個(gè)字典。該字典有3個(gè)鍵值。

{
    'encoding': 'GB2312',
    'confidence': 0.99,
    'language': 'Chinese'
}

encoding是所識別出來該二進(jìn)制序列的編碼方式。
confidence是所識別出來的encoding正確概率(1.0表示100%)。
language是該編碼方式適用的語言。
可以根據(jù)confidence概率決定是否使用encoding編碼方式。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容