在Python 2.5中解码未知unicoding编码的最佳方法

8 投票
3 回答
12319 浏览
提问于 2025-04-15 15:54

我这样理解对吗?不管怎样,我正在处理很多HTML代码,但我并不总是知道它应该用什么编码(很多时候它们会撒谎)。下面的代码展示了我到目前为止的做法,但我相信还有更好的方法。希望你们能给我一些建议。

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.")

3 个回答

2

既然你在用Python,可以试试UnicodeDammit。这个工具是Beautiful Soup的一部分,可能对你也有帮助。

顾名思义,UnicodeDammit会尽力从你在网上遇到的各种乱七八糟的东西中提取出正确的unicode编码。

3

我也遇到过同样的问题,发现没有内容的元数据就无法确定它的编码类型。这就是我最后选择和你一样的方法的原因。

我对你所做的唯一额外建议是,不要按照最可能的顺序来排列可能的编码列表,而是按特定性来排列。我发现某些字符集是其他字符集的子集,所以如果你把utf_8作为第二选择来检查,你可能会错过utf_8的子集(我记得有一种韩文字母的字符集使用了和utf相同的数字空间)。

10

有两个通用的库可以用来检测未知的编码方式:

chardet可以理解为是Firefox处理编码的方式的一个移植版。

你可以使用下面的正则表达式来检测字节字符串是否是utf8编码:

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,那就假设是latin-15编码。
  4. 否则就假设是latin-1编码。

撰写回答