【问题标题】:Ignore UTF-8 decoding errors in CSV忽略 CSV 中的 UTF-8 解码错误
【发布时间】:2019-09-19 16:05:20
【问题描述】:

我有一个 CSV 文件(我无法控制)。这是连接多个 CSV 文件的结果。大部分文件是 UTF-8,但其中一个文件的字段编码格式类似于 Windows-1251。

我实际上只关心包含 URL 的字段之一(因此它是有效的 ASCII/UTF-8)。

如果我只关心一个我知道是 ASCII 的字段,我如何忽略其他 CSV 字段中的解码错误?或者,对于更有用的解决方案,如果出现编码错误,如何更改 CSV 文件每一行的编码?

【问题讨论】:

  • 只需将其作为具有 256 个代码点的字符集的任何字符编码来读取,每个字符集用 1 个字节编码,前 128 个代码点与 ASCII 相同。例如,ISO 8859-1。有些文字会是错误的,但你描述的那一列。
  • 如果不关心 UTF-8 字符串的完整性,可以直接读取为 Windows-1252 即可。
  • @tripleee 我认为这也是 Tom 的建议。

标签: python utf-8 character-encoding


【解决方案1】:

csv.reader 和 csv.DictReader 将字符串列表(行列表)作为输入,而不仅仅是文件对象。

因此,以二进制模式 (mode="rb") 打开文件,找出每一行的编码,使用该编码解码该行并将其附加到一个列表中,然后在该列表上调用 csv.reader。

一个简单的启发式方法是尝试将每一行读取为 UTF-8,如果您得到 UnicodeDecodeError,请尝试将其解码为其他编码。如果您无法将其解码为 UTF-8,我们可以使用chardet library(与pip install chardet 一起安装)来猜测每行的编码,而不是硬编码要依赖的编码,从而使其更通用:

import codec

my_csv = "some/path/to/your_file.csv"

lines = []
with open(my_csv, "rb") as f:
    for line in f:
        detected_encoding = chardet.detect(line)["encoding"]
        try:
            line = line.decode("utf-8")
        except UnicodeDecodeError as e:
            line = line.decode(detected_encoding)
        lines.append(line)

reader = csv.DictReader(lines)
for row in reader:
    do_stuff(row)

如果您确实只想硬编码后备编码并且不想使用chardet(有一个很好的理由不这样做,它并不总是准确的),您可以替换变量detected_encoding 与 "Windows-1251" 或 whatever encoding 在上面的代码中。

这当然不是完美的,因为仅仅因为一行使用某种编码成功解码并不意味着它实际上正在使用该编码。如果您不必多次执行此操作,最好执行打印每一行及其检测到的编码之类的操作,并尝试找出一种编码从哪里开始,而另一种则手动结束。最终,在这里追求的正确策略可能是尝试逆转导致输入损坏的步骤(文件的连接),然后正确地重新执行(通过在连接之前将它们标准化为相同的编码)。

就我而言,我计算了检测到的编码行数

import chardet
from collections import Counter

my_csv_file = "some_file.csv"
with open(my_csv_file, "rb") as f:
   encodings = Counter(chardet.detect(line)["encoding"] for line in f)

print(encodings)

并意识到我的整个文件实际上是用其他第三种编码编码的。在整个文件上运行chardet 检测到错误的编码,但在每一行上运行它检测到一堆编码,第二个最常见的编码(在ascii 之后)是我需要用来读取整个文件的正确编码。所以最终我需要的只是

with open(my_csv, encoding="latin_1") as f:
    reader = csv.DictReader(f)
    for row in reader:
        do_stuff(row)

您可以尝试使用Compact Encoding Detection 库而不是chardet。这是谷歌浏览器使用的,所以也许它会更好,但它是用 C++ 而不是 Python 编写的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-03
    • 2015-03-04
    • 2016-06-01
    相关资源
    最近更新 更多