2009-11-11 15 views
6

我是否已經完全正確了?無論如何,我正在解析很多HTML,但我並不總是知道它的意思是什麼編碼(一個令人驚訝的數字謊言)。下面的代碼很容易地顯示了我到目前爲止所做的工作,但我確信有更好的方法。您的建議將不勝感激。在Python 2.5中解碼未知的單一編碼的最佳方法

import logging 
import codecs 
from utils.error import Error 

class UnicodingError(Error): 
    pass 

# these encodings should be in most likely order to save time 
encodings = [ "ascii", "utf_8", "big5", "big5hkscs", "cp037", "cp424", "cp437", "cp500", "cp737", "cp775", "cp850", "cp852", "cp855", 
    "cp856", "cp857", "cp860", "cp861", "cp862", "cp863", "cp864", "cp865", "cp866", "cp869", "cp874", "cp875", "cp932", "cp949", 
    "cp950", "cp1006", "cp1026", "cp1140", "cp1250", "cp1251", "cp1252", "cp1253", "cp1254", "cp1255", "cp1256", "cp1257", "cp1258", 
    "euc_jp", "euc_jis_2004", "euc_jisx0213", "euc_kr", "gb2312", "gbk", "gb18030", "hz", "iso2022_jp", "iso2022_jp_1", "iso2022_jp_2", 
    "iso2022_jp_2004", "iso2022_jp_3", "iso2022_jp_ext", "iso2022_kr", "latin_1", "iso8859_2", "iso8859_3", "iso8859_4", "iso8859_5", 
    "iso8859_6", "iso8859_7", "iso8859_8", "iso8859_9", "iso8859_10", "iso8859_13", "iso8859_14", "iso8859_15", "johab", "koi8_r", "koi8_u", 
    "mac_cyrillic", "mac_greek", "mac_iceland", "mac_latin2", "mac_roman", "mac_turkish", "ptcp154", "shift_jis", "shift_jis_2004", 
    "shift_jisx0213", "utf_32", "utf_32_be", "utf_32_le", "utf_16", "utf_16_be", "utf_16_le", "utf_7", "utf_8_sig" ] 

def unicode(string): 
    '''make unicode''' 
    for enc in self.encodings: 
     try: 
      logging.debug("unicoder is trying " + enc + " encoding") 
      utf8 = unicode(string, enc) 
      logging.info("unicoder is using " + enc + " encoding") 
      return utf8 
     except UnicodingError: 
      if enc == self.encodings[-1]: 
       raise UnicodingError("still don't recognise encoding after trying do guess.") 
+0

自動檢測知道*絕對沒有*關於你的文字,但如果你知道,至少在語言文字中有隻有極少數的選擇。這就是爲什麼編碼檢測基本上意味着試圖根據字母的頻率來猜測語言。 – 2009-11-11 15:50:26

+0

Erm,unicode()返回Unicode而不是UTF-8。 – 2009-11-11 15:51:37

回答

8

存在用於檢測未知的編碼兩個通用庫:

chardet的部分被認爲是所述way that firefox does it的端口

您可以使用下面的正則表達式從字節串檢測UTF8 S:

import re 

utf8_detector = re.compile(r"""^(?: 
    [\x09\x0A\x0D\x20-\x7E]   # ASCII 
    | [\xC2-\xDF][\x80-\xBF]    # non-overlong 2-byte 
    | \xE0[\xA0-\xBF][\x80-\xBF]  # excluding overlongs 
    | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte 
    | \xED[\x80-\x9F][\x80-\xBF]  # excluding surrogates 
    | \xF0[\x90-\xBF][\x80-\xBF]{2}  # planes 1-3 
    | [\xF1-\xF3][\x80-\xBF]{3}   # planes 4-15 
    | \xF4[\x80-\x8F][\x80-\xBF]{2}  # plane 16 
)*$""", re.X) 

在實踐中,如果你處理的是英語,我發現下面的工作時間99.9%:

  1. 如果通過上述正則表達式,它是ASCII或UTF8
  2. 如果它包含從0x80-0x9f但不0xa4任何字節,這是Windows的1252
  3. 如果它包含0xa4,假設它的拉丁-15
  4. 否則假定它的拉丁-1
+1

我把它編碼並放在這裏http:// pastebin。com/f76609aec – user132262 2009-11-12 12:50:49

+0

您粘貼的代碼存在問題:如果字符串*完全*'\ xA4'且沒有其他字符,'^(?:\ xA4)* $'將匹配。對於其他兩個正則表達式,您只需要're.compile(r'\ xA4')'和're.compile(r'[\ x80- \ xBF]')''。 – 2009-11-12 13:35:42

1

由於您使用的是Python,因此您可以嘗試UnicodeDammit。它也是Beautiful Soup的一部分,您也可能會覺得有用。

喜歡這個名字所暗示的,UnicodeDammit將試圖不惜一切代價來獲得適當的Unicode了,你可以在世界上找到的廢話。

+0

儘早嘗試過,但失敗了很多。 – user132262 2009-11-11 16:20:34

+0

真的!有什麼問題?得到這個工作可能比推出自己的工作更容易。 – 2009-11-11 17:28:58

+0

「你可能在世界上找到的廢話」? – Sabuncu 2012-05-06 06:10:41

2

我已經解決了同樣的問題,發現沒有辦法來確定內容的編碼類型沒有關於內容的元數據。這就是爲什麼我最終採用了你在這裏嘗試的相同方法。

我唯一的附加建議你做了什麼的,而不是在排序最可能的順序可能編碼的列表,你應該特異性訂購。我發現,某些字符集是其他的子集,所以如果你檢查utf_8作爲你的第二個選擇,你會想念曾經發現的utf_8的子集(我覺得韓文字符集的一個使用相同數量的空間爲utf )。

+0

確實。 'ascii'是'utf-8'的一個子集,並且也可以正確解碼爲'utf-8',所以你可以離開'ascii'。在所有情況下,8位編碼(如latin-1)將解碼爲_something_,因此將其中一個最後編碼。 – Thomas 2009-11-11 15:22:04

相關問題