Rop*_*tah 5 python character-encoding
我有一个编码的文本文件,utf-16它会引发以下字符的异常:'\u0153'.
UnicodeEncodeError:'charmap'编解码器无法对字符'\ u0153'进行编码
我正在使用一个非常简单的脚本来加载文件,我也尝试忽略错误而无济于事.我究竟做错了什么?
with open(filename, "r", encoding="utf-16", errors='replace') as data_file:
print(data_file.read())
Run Code Online (Sandbox Code Playgroud)
这是文件的一部分,它打破了:
["Xinhua","Ürümqi"]
编辑: 不知道为什么我的问题被误解了.希望这是更好的形成.
我该如何用Python阅读这个文件?
示例文件链接(UTF-16-LE文件)包含:
["Xinhua","Ürümqi"]
为什么这段代码不起作用?
with open(filename, "r", encoding="utf-16", errors='replace') as data_file:
print(data_file.read())
Run Code Online (Sandbox Code Playgroud)
最初困扰你的例外是因为你在终端模拟器中运行Python(或者可能是"控制台窗口"是一个更熟悉的术语?),它无法显示Unicode中的所有字符.要解决这个问题,你需要让自己拥有一个支持Unicode的终端模拟器,然后确保Python 知道它在支持Unicode的终端模拟器中运行.如果您不知道如何操作,请在superuser.com上提出一个新问题,指定您的操作系统.
我的终端模拟器可以显示Unicode中的所有字符,假设所有必需的字体都可用,并且Python知道这一点,所以我可以这样做而不会得到异常:
>>> with open("countryCity2.json", "r", encoding="utf-16") as f:
... x = f.read()
...
>>> print(x)
["Xinhua","Ürümqi"]
Run Code Online (Sandbox Code Playgroud)
但是,这不是你唯一的问题.您的输入文件已编码其编码.Ürümqi不是任何语言中有意义的字符序列.但是,它符合已经从遗留编码转换为UTF-8的文本的特征mojibake模式,然后 - 错误地 - 再次转换为Unicode编码.我们可以通过将它1:1转换为字节并查看是否获得有效的UTF-8字节序列来测试它:
>>> print(x.encode("iso-8859-1").decode("utf-8"))
["Xinhua","Ürümqi"]
Run Code Online (Sandbox Code Playgroud)
" Ürümqi "是一个真实的词,可能与" 新华 " 一起出现.此外,如果文本没有被错误转换为UTF-8,我们会看到一个例外:
>>> "Ürümqi".encode("iso-8859-1").decode("utf-8")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xdc in position 0:
invalid continuation byte
Run Code Online (Sandbox Code Playgroud)
所以这个假设得到了证实.
在一个必须处理大量文件的程序中,这些文件的编码可能会或可能不会以这种方式被破坏,我会做这样的事情:
for fname in input_files:
with open(fname, "r", encoding="utf-16") as f:
contents = f.read()
try:
contents = contents.encode("iso-8859-1").decode("utf-8")
except (UnicodeEncodeError, UnicodeDecodeError):
pass
process_file(fname, contents)
Run Code Online (Sandbox Code Playgroud)
我在这里使用ISO 8859.1编码并不是因为文本实际上或者实际上是在那个编码中,而是因为Python的iso-8859-1编解码器是从字符U + 0000..U + 00FF到字节0x00..0xFF的身份映射.(从技术上讲,这意味着它实现了IANA ISO_8859-1:1987而不是原始的ECMA-94:1985代码页,这使得0x00..0x1F和0x7F..0x9F范围未定义.)即,
>>> "".join(chr(c) for c in range(256)).encode('iso-8859-1') == bytes(range(256))
True
Run Code Online (Sandbox Code Playgroud)
因此,只要您将二进制数据错误地转换为Unicode,就可以恢复原始数据.encode('iso-8859-1').
注意:上面的所有代码片段都是Python 3.
| 归档时间: |
|
| 查看次数: |
7953 次 |
| 最近记录: |