Python 3 读取 CP-1252/ANSI 时崩溃
我正在做一系列解析器,处理从单元测试中得到的一些错误信息,比如:
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 个回答
所有文件都不是“Unicode”。Unicode是一种内部表示方式,需要进行编码。你需要确定每个文件使用了什么编码,并在打开文件时根据需要指定这个编码。
根据错误信息和追踪信息,这个文件显然不是用cp1252
编码的。
如果它是用latin1
编码的,那么它提到的"\x81"
是一个C1控制字符,甚至在Unicode中都没有名字。可以认为latin1
几乎不可能是有效的。
你说“有些文件是用xml.dom.minidom解析的”——是成功解析还是失败了呢?
一个有效的XML文件应该在第一行声明它的编码(默认是UTF-8),你在代码中不应该需要指定编码。请给我们看看你用来进行xml.dom.minidom解析的代码。
“其他文件直接作为可迭代对象读取”——请提供示例代码。
建议:尝试在浏览器中打开每种类型的文件。然后点击查看,再点击字符编码(在Firefox中)或编码(在Internet Explorer中)。浏览器猜测的编码是什么[通常是可靠的]?
其他可能的编码线索:文件中的文本使用了什么语言?你从哪里获得这些文件的?
注意:请编辑你的问题,添加更多澄清信息;不要在评论中回答。
在Windows-1252(也叫cp1252)编码中,位置0x81是没有分配的。而在Latin-1(也叫ISO 8859-1)编码中,它被分配给了U+0081这个控制字符,叫做高八位预设(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来处理,你需要传递一个encoding
参数,就像codeape建议的那样:
>>> open('test.txt', encoding='latin-1').read()
'\x81\n'
要注意,Windows-1257和Latin-1编码之间是有区别的,比如Latin-1没有“智能引号”。如果你正在处理的是一个文本文件,想想看这个\x81在里面是干嘛的。