Python 3在读取CP-1252/ANSI编码的文件时出现错误

6

我正在开发一系列解析器,在其中执行单元测试时,会出现大量的回溯信息,例如:

  File "c:\Python31\lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 112: character maps to <undefined>

文件是使用open()打开的,没有额外的参数。我能否向open()传递额外的参数或者使用codec模块中的内容来以不同的方式打开这些文件呢?
这个问题出现在用Python 2编写并用2to3工具转换成Python 3的代码中。
更新:原来这是由于将zipfile馈送到解析器中造成的。测试单元实际上希望发生这种情况。解析器应该识别它为不能解析的内容。所以,我需要改变我的异常处理。我正在进行这方面的工作。
3个回答

15

Windows-1252(也称为cp1252)中未分配0x81位置。在Latin-1(也称为ISO 8859-1)中,它被分配给U+0081 HIGH OCTET PRESET(HOP)控制字符。我可以通过以下方式在Python 3.1中重现您的错误:

>>> b'\x81'.decode('cp1252')
Traceback (most recent call last):
  ...
UnicodeDecodeError: 'charmap' codec can't decode byte 0x81 in position 0: character maps to <undefined>

或者使用实际文件:

>>> open('test.txt', 'wb').write(b'\x81\n')
2
>>> open('test.txt').read()
Traceback (most recent call last):
  ...
UnicodeDecodeError: 'utf8' codec can't decode byte 0x81 in position 0: unexpected code byte

现在如果您想将该文件视为Latin-1格式,可以像codeape建议的那样传递encoding参数:

>>> open('test.txt', encoding='latin-1').read()
'\x81\n'

请注意 Windows-1257 和 Latin-1 编码之间存在差异,例如 Latin-1 没有“智能引号”。

如果您正在处理的文件是文本文件,请问一下其中的 \x81 是什么意思。


FWIW,Latin-1具有所有256个代码点分配,因此您永远不会遇到UnicodeDecodeError。但是您可能会破坏数据。 - Marius Gedminas

4
你可以放宽错误处理。
例如:
f = open(filename, encoding="...", errors="replace")

或者:

f = open(filename, encoding="...", errors="ignore")

请看文档编辑: 但是你确定问题出在读取文件上吗?有可能是在向控制台写入时发生异常吗?请查看http://wiki.python.org/moin/PrintFails

我尝试了这两个,结果一样。在输出之前就抛出了错误。 - Aaron Altman
2
“放宽错误处理”没有任何线索表明正在忽略什么或为什么 - 这是毫无意义的屠戮。 - John Machin
确实,忽略编码错误是一种不良的做法,违反了Unicode标准。 - Philipp
@altie:错误可能是由于向控制台写入某些内容引起的。 - codeape
谢谢,这非常有帮助。我的情况是我有一些文本日志,其中偶尔包含二进制数据,我想使用正则表达式和处理它们。 - jnnnnn

2
所有文件都是“非Unicode”的。Unicode是一种内部表示,必须进行编码。您需要确定每个文件使用了哪种编码,并在打开文件时在必要时指定该编码。
正如回溯和错误消息所示,问题中的文件没有使用cp1252编码。
如果它使用的是latin1编码,则它抱怨的"\x81"是一个没有名称(在Unicode中)的C1控制字符。考虑latin1极不可能有效。
您说“有些文件使用xml.dom.minidom解析”——成功还是失败?
有效的XML文件应在第一行声明其编码(默认为UTF-8),您不需要在代码中指定编码。向我们展示您用于进行xml.dom.minidom解析的代码。
“其他直接读取为可迭代对象”——请提供示例代码。
建议:尝试在浏览器中打开每种类型的文件。然后单击“查看”,再单击“字符编码”(Firefox)或“编码”(Internet Explorer)。浏览器猜测的编码是什么[通常可靠]?
其他可能的编码线索:文件中使用了哪些语言?您从哪里获取这些文件?
注意:请使用澄清信息编辑您的问题;不要在评论中回答。

这可能是一个DOS代码页,在其中'\x81'通常是'ü'。 - dan04

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