如何在Python中解码非Unicode字符?

6
我是一个有用的助手,可以翻译文本。

我有一个字符串,比如说s = 'Chocolate Moelleux-M\xe8re'当我执行:

In [14]: unicode(s)
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 20: ordinal not in range(128)

同样地,当我尝试使用 s.decode() 进行解码时,它返回相同的错误。
In [13]: s.decode()
---------------------------------------------------------------------------
UnicodeDecodeError                        Traceback (most recent call last)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 20: ordinal not in range(128)

如何将此类字符串解码为Unicode。
2个回答

11

我已经面对这个问题太多次了。我的问题涉及到不同编码方案中的字符串。因此,我编写了一种方法,根据不同编码的某些特征启发式地解码字符串。

def decode_heuristically(string, enc = None, denc = sys.getdefaultencoding()):
    """
    Try to interpret 'string' using several possible encodings.
    @input : string, encode type.
    @output: a list [decoded_string, flag_decoded, encoding]
    """
    if isinstance(string, unicode): return string, 0, "utf-8"
    try:
        new_string = unicode(string, "ascii")
        return string, 0, "ascii"
    except UnicodeError:
        encodings = ["utf-8","iso-8859-1","cp1252","iso-8859-15"]

        if denc != "ascii": encodings.insert(0, denc)

        if enc: encodings.insert(0, enc)

        for enc in encodings:
            if (enc in ("iso-8859-15", "iso-8859-1") and
                re.search(r"[\x80-\x9f]", string) is not None):
                continue

            if (enc in ("iso-8859-1", "cp1252") and
                re.search(r"[\xa4\xa6\xa8\xb4\xb8\xbc-\xbe]", string)\
                is not None):
                continue

            try:
                new_string = unicode(string, enc)
            except UnicodeError:
                pass
            else:
                if new_string.encode(enc) == string:
                    return new_string, 0, enc

        # If unable to decode,doing force decoding i.e.neglecting those chars.
        output = [(unicode(string, enc, "ignore"), enc) for enc in encodings]
        output = [(len(new_string[0]), new_string) for new_string in output]
        output.sort()
        new_string, enc = output[-1][1]
        return new_string, 1, enc

为此,这个链接在为什么需要编码等方面提供了很好的反馈 - 为什么我们需要在Python脚本中使用sys.setdefaultencoding('utf-8')


4
您需要告诉 s.decode 您的编码方式。在您的情况下,s.decode('latin-1') 似乎是合适的选择。

这会在所有情况下都对我有帮助吗?有没有通用的解决方案? - user12345
我们能否从原始字符串中删除那些像'\x'一样的字符,就像我的例子一样? - user12345
@alis:你可以使用 chardet(http://chardet.feedparser.org/)来猜测编码。 - johnbaum
s.decode('ascii','ignore') 将删除所有“奇怪”的字符。 - Habbie
3
@alis提到将Chocolate Moelleux-Mère转换为Chocolate Moelleux-Mre。我不理解这怎么可能是实际的解决方案。另外,假设你遇到一个编码为ISO-8859-5的Мойст Шоколад Матери版本。如果你忽略所有非ASCII字符解码,剩下的只有两个空格。换句话说,请通过指定匹配的编码来解码字符串。在你的例子中,使用unicode(s, 'latin-1')来解码。 - Bernd Petersohn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接