Python 加载 'utf-16' 文件无法解码 '\u0153'

Python loading 'utf-16' file can't decode '\u0153'

我有一个编码为 utf-16 的文本文件,它会为以下字符抛出异常:'\u0153'.

UnicodeEncodeError: 'charmap' codec can't encode character '\u0153' in position

我正在使用一个非常简单的脚本来加载文件,而且我还尝试了 忽略 错误但无济于事。我做错了什么?

with open(filename, "r", encoding="utf-16", errors='replace') as data_file:    
    print(data_file.read())

这是破坏文件的一部分:

["Xinhua","Ürümqi"]

编辑: 不知道为什么我的问题被误解了。希望这是更好的形式。

我应该如何用 Python 阅读这个文件?

Sample file link(UTF-16-LE 文件)包含:

["Xinhua","Ürümqi"]

为什么这段代码不起作用?

with open(filename, "r", encoding="utf-16", errors='replace') as data_file:    
    print(data_file.read())

最初难倒您的异常是因为您在终端仿真器中 运行 Python(或者可能 "console window" 是一个更熟悉的术语?)无法显示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"]

但是,这不是您唯一的问题。您的输入文件的编码已损坏。 Ürümqi 不是在任何语言中都有意义的字符序列。但是,它符合已从传统编码转换为 UTF-8,然后又错误地转换为 Unicode 编码 的文本特征 mojibake 模式。我们可以通过将它 1:1 转换为字节并查看我们是否获得有效的 UTF-8 字节序列来测试它:

>>> print(x.encode("iso-8859-1").decode("utf-8"))
["Xinhua","Ürümqi"]

"Ürümqi" is a real word and would plausibly appear in conjunction with "Xinhua"。另外,如果文本没有被错误转换为 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

假设成立

在一个必须处理大量文件的程序中,这些文件的编码可能会或可能不会以这种方式被破坏,我会这样做:

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)

我在这里使用 ISO 8859.1 编码 而不是 因为文本实际上是或曾经使用该编码,但是因为 Python 的 iso-8859-1 codec是从字符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

因此,任何时候您的二进制数据被错误转换为 Unicode,您都可以使用 .encode('iso-8859-1') 恢复原始数据。

注意: 以上所有代码片段都是 Python 3.

我的答案在 Python3.5 上工作并忽略所有变形的字符,所以目标是在 try 块中打印正确的字符,在块中除了你可以在块中使用 pass除了,或者打印它们并使用 encode() 对它们进行编码

from codecs import open
with open("C:/test2/trans1", "r", "utf-8") as f:
    lines = f.readlines()
    f.close()
for ligne in lines:
    try:
        print(ligne.rstrip())
    except UnicodeEncodeError:
        print(ligne.rstrip().encode())