[Python模塊學習]chardet模塊識別字節包編碼

chardet模塊

by: uizuizui

這個模塊是the auto-detection code in Mozilla的一部分源碼加上模塊作者的一些改進而成的。模塊作者保留了源代碼作者代碼註釋。


功能描述:chardet模塊即Universal Encoding Detector,功能正如其名,是一個用於字符檢測的模塊。它可以幫助我們識別一段未知格式的字節是屬於什麼編碼格式。從而可以順利地將bytes轉換爲str。


安裝: pip install chardet


簡單用法

chardet的使用非常簡單,主模塊裏面只有一個函數detect。detect有一個參數,要求是bytes類型。bytes類型可以通過讀取網頁內容、open函數的rb模式、帶b前綴的字符串、encode函數等途徑獲得。

示例代碼:

import chardet

some_string = '你好,世界。'.encode('utf-8') # encode方法返回一個bytes
# b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xe3\x80\x82'

result = chardet.detect(some_string) # 調用檢測接口

print(result)
# {'encoding': 'utf-8', 'confidence': 0.99}

如上所示,detect函數返回一個字典,字典裏有兩個key-value對。其中一個的key值爲encoding,代表chardet推斷出來的編碼格式。另一個key值爲confidence,代表可信度。可信度是一個0到1之間float值,0代表不可信,1代表百分之百可信。


高級用法

當用於檢測的文檔特別大時,可以chardet的子模塊chardet.universaldetector。這個模塊允許我們分多次(逐行讀取或者自行斷行讀取)檢測文本的編碼格式,當達到一定的閾值時便可以提前退出檢測。這樣做可以有效地節省資源,提高程序效率,同時保證檢測結果的準確性。

示例代碼:

from chardet.universaldetector import UniversalDetector

detector = UniversalDetector() # 初始化一個UniversalDetector對象
f = open('test.txt', 'rb') # test.txt是一個utf-8編碼的文本文檔

for line in f:
    detector.feed(line) # 逐行載入UniversalDetector對象中進行識別
    if detector.done: # done爲一個布爾值,默認爲False,達到閾值時變爲True
        break

detector.close() # 調用該函數做最後的數據整合
f.close()
print(detector.result)
# {'confidence': 1.0, 'encoding': 'UTF-8-SIG'}

需要注意的是:如果對多個不同來源的文本進行檢測,在每次檢測完畢時,必須調用一次UniversalDetector對象的reset函數,將之前的檢測數據清除。否則會導致後面的檢測結果混亂。


目前支持的編碼格式

Universal Encoding Detector目前支持以下編碼格式:

  • Big5, GB2312/GB18030, EUC-TW, HZ-GB-2312, and ISO-2022-CN (Traditional and Simplified - Chinese 繁體和簡體中文)
  • EUC-JP, SHIFT_JIS, and ISO-2022-JP (Japanese 日文)
  • EUC-KR and ISO-2022-KR (Korean 韓文)
  • KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, and windows-1251 (Russian 俄文)
  • ISO-8859-2 and windows-1250 (Hungarian 匈牙利文)
  • ISO-8859-5 and windows-1251 (Bulgarian 保加利亞文)
  • ISO-8859-1 and windows-1252 (Western European languages 西歐文字)
  • ISO-8859-7 and windows-1253 (Greek 希臘文)
  • ISO-8859-8 and windows-1255 (Visual and Logical Hebrew 視覺順序和邏輯順序的希伯來文)
  • TIS-620 (Thai 泰文)
  • UTF-32 BE, LE, 3412-ordered, or 2143-ordered (with a BOM 帶字節序標記)
  • UTF-16 BE or LE (with a BOM 帶字節序標記)
  • UTF-8 (with or without a BOM 帶或者不帶字節序標記)
  • ASCII

注意:由於內部的相似性,某些情況下會出現檢測錯誤。最常出問題的是匈牙利文,會出現報告的編碼是兩種之中的另一種。希臘文的檢測也經常錯誤的將ISO-8859-7識別爲匈牙利文的ISO-8859-2。


關於檢測時出現的奇怪錯誤

該模塊在檢測ANSI編碼(在中文版windows系統上就是gbk)的時候會出現一些奇怪的錯誤,博主正在研究英文文檔,希望能在上面找到答案。如果有後續,會同步更新至本文。

接上文:

問題來源:某些情況下檢測ANSI編碼的文本文檔和gb2312編碼的字節包會出現錯誤。

過程:博主分別對不同情況下錄入、不同長度和不同編碼的字節包進行了測試。並仔細看了一遍官方文檔。大概理出了個思路。

解析:官方文檔上有一段話,我先原文摘下來。

If UniversalDetector detects a high-bit character in the text, but none of the other multi-byte or single-byte encoding probers return a confident result, it creates a Latin1Prober (defined in latin1prober.py) to try to detect English text in a windows-1252 encoding. This detection is inherently unreliable, because English letters are encoded in the same way in many different encodings. The only way to distinguish windows-1252 is through commonly used symbols like smart quotes, curly apostrophes, copyright symbols, and the like. Latin1Prober automatically reduces its confidence rating to allow more accurate probers to win if at all possible.

大概意思是,當UniversalDetector在解析一些字節的時候,如果沒有相應的探測器給出報告,它就會調用一個叫做Latin1Prober的探測器試圖用英文編碼windows-1252來解析該字節包,這個探測器非常不可信(官方吐槽…)。通常情況下英文字母和一些特殊符號在不同的編碼裏是一樣的,所以這個探測器會給出很高的可信度。這個探測器會自動地壓低自己給出的可信度以讓其他探測器可以優先通過。

再根據以下這段原文:

The main entry point for the detection algorithm is universaldetector.py, which has one class, UniversalDetector. (You might think the main entry point is the detect function in chardet/init.py, but that’s really just a convenience function that creates a UniversalDetector object, calls it, and returns its result.)

大致意思是:檢測算法的入口是UniversalDetector,chardet.detect函數僅僅只是方便用戶使用的語法糖。

可以得出類似的機制也會出現在detect函數中。儘管Latin1Prober已經做了優化,但是還是會有一些情況下它給出了遠超實際的可信度。比如下面這個實驗:

>>> import chardet
>>> chardet.detect('哈'.encode('gb2312'))
{'confidence': 0.73, 'encoding': 'windows-1252'}

博主還做了幾個其他的實驗,得出了一個結論:當字節包的長度不夠長時,chardet給出的結論是很不可靠的,因爲它可能在調用一個不相干的探測器時,該探測器給出了一個超過閾值的可信度,或者兩個編碼格式剛好有共通的字符,然後就不再往下檢測。這麼做很容易出現不可靠的檢測結果。所以最好不要檢測很少量的字節。同時,在檢測開篇有大段其他字符的文檔時,最好先手動處理掉無關的符號(不一定會發生錯誤,因爲程序根據初次遍歷結果對探測器的順序做了優先級排序,但是保不準會出錯),以求最準確的結果。

How Universal Encoding Detector Works這個網址詳細地說明了模塊是如何運作的。建議能看懂英文並且有耐心的讀者通讀一遍。博主只是選擇性地快速閱讀了一遍,不能保證把原作者的意思傳達到各位這裏,但是也能保證偏差不會太大。


參考資料:
chardet doc
python 模塊 chardet下載方法及介紹

感謝以上模塊提供者和內容提供者

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