【问题标题】:Best way to decode unknown unicoding encoding in Python 2.5 [duplicate]在 Python 2.5 中解码未知编码编码的最佳方法 [重复]
【发布时间】:2010-12-15 12:07:25
【问题描述】:

我的方法完全正确吗?无论如何,我正在解析很多 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.")

【问题讨论】:

  • 自动检测对您的文本一无所知,但如果您至少知道文本所使用的语言,则只有很少的选项。这就是为什么编码检测基本上意味着尝试根据字母的频率猜测语言。
  • 呃,unicode() 返回 Unicode 而不是 UTF-8。

标签: python html unicode encoding character-encoding


【解决方案1】:

有两个用于检测未知编码的通用库:

chardet 应该是 way that firefox does it 的一个端口

您可以使用以下正则表达式从字节字符串中检测 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

【讨论】:

  • 我把它编码并放在这里pastebin.com/f76609aec
  • 您粘贴的代码有问题:^(?:\xA4)*$ 将匹配如果字符串是完全 \xA4 并且没有其他字符。对于其他两个正则表达式,您只需要 re.compile(r'\xA4')re.compile(r'[\x80-\xBF]')
【解决方案2】:

我已经解决了同样的问题,发现如果没有关于内容的元数据,就无法确定内容的编码类型。这就是为什么我最终采用了您在这里尝试的相同方法。

我对您所做工作的唯一额外建议是,您应该按特定顺序排列可能的编码列表,而不是按最可能的顺序排列。我发现某些字符集是其他字符集的子集,因此如果您将utf_8 作为第二选择,您将错过找到utf_8 的子集(我认为其中一个韩语字符集使用相同数字空间为 utf)。

【讨论】:

  • 确实如此。 asciiutf-8 的一个子集,也可以正确解码为utf-8,因此您可以将ascii 排除在外。在所有情况下,latin-1 等 8 位编码都会解码为 something,因此请将其中之一放在最后。
【解决方案3】:

由于您使用的是 Python,您可以尝试UnicodeDammit。它是Beautiful Soup 的一部分,您也可能会发现它很有用。

顾名思义,UnicodeDammit 将尽一切努力从世界上可能发现的垃圾中获取正确的 unicode。

【讨论】:

  • 很早就试过了,但失败了很多。
  • 真的!有什么问题?让它发挥作用可能比自己动手更容易。
  • “你可能在世界上找到的垃圾”?
猜你喜欢
  • 1970-01-01
  • 2011-02-08
  • 2010-11-26
  • 1970-01-01
  • 2018-03-08
  • 2016-05-12
  • 2012-11-29
  • 2010-11-04
  • 2010-11-08
相关资源
最近更新 更多