【问题标题】:Can you skip non utf-8 data in python csv?你可以跳过 python csv 中的非 utf-8 数据吗?
【发布时间】:2015-05-15 15:34:11
【问题描述】:

我正在处理 python 中的一个非常大的 csv 文件,其中一些行抛出错误“'utf-8' codec can't decode byte 0x9b in position 7657: invalid start byte”。有没有办法在不手动删除或修复数据的情况下跳过不是 utf-8 的行?

for filename in filenames:
f = open(filename, 'rt')
reader = csv.reader(f, delimiter = ',')
for row in reader:
    #process data for future use

我不能使用非utf8的数据,因为后面的进程需要使用utf-8

【问题讨论】:

  • 您的文件是否以 UTF-8 编码并且损坏了?或者它实际上是在其他一些你应该正确处理的编码中?
  • 或者您是否尝试将数据打印到非 UTF-8 终端(如在 Windows 上)?
  • 你应该展示你的代码,你可以添加一个try except,当这个特定的错误出现时它就会通过。但这意味着会丢失一些数据。
  • 正如您所说的 UTF8,Python 版本 2 和 3 的行为会有所不同。你想要 Python2 还是 Python3?

标签: python csv utf-8


【解决方案1】:

您可以使用过滤器将一行读取为原始字节,尝试将其转换为 UTF8 的 unicode,然后:

  • 如果成功,将其传递给 csv 阅读器
  • 如果没有,则将其存储以供以后分析

假设您使用的是 Python2,您可以使用类似:

class MyFilter:
    def __init__(self, instr, errstr):
        self.instr = instr
        self.errstr = errstr
    def __enter__(self):
        print("ENTERING filter")
        return self
    def __exit__(self, a, b, c):
        print("EXITING filter")
        self.instr.close()
        self.errstr.close()
        return False
    def __next__(self):
        line = next(self.instr)
        while True:
            try:
                t = line.decode('utf8')
                return line.strip()
            except UnicodeDecodeError:
                self.errstr.write(line)
                line = next(self.instr)
        return line
    def __iter__(self):
        return self
    def next(self):
        return self.__next__()

然后您可以这样使用它(假设 Python 2.7),在 err.txt 中获取所有违规行:

with open('file.csv') as istream, open("err.txt", 'w') as err, MyFilter(istream, err) as fd:
    c = csv.reader(fd)
    for i in c:
        # do you stuff, eg: print i

如果您使用 Python 3,则可以使用几乎相同的过滤器类,只需将行 return line.strip() 替换为 return t.strip(),以便返回字符串而不是字节。

用法也几乎相同:

with open('file.csv', 'rb') as istream, open("err.txt", 'wb') as err, MyFilter(istream, err) as fd:
    c = csv.reader(fd)
    for i in c:
        # do you stuff, eg: print (i)

根据您的评论,您还想过滤包含空字符的行。这只需要稍微改变过滤器,while 块变成(Python 3 版本):

    while True:
        if b'\x00' not in line:
            try:
                t = line.decode('utf8')
                return t.strip()
            except UnicodeDecodeError:
                pass
        self.errstr.write(line)
        line = next(self.instr)

【讨论】:

  • @NimishTodi : 如果你只使用 Python 3,你可以删除最后一个方法 def next(self): return self.__next__(),它只存在于 Python 2 兼容性。
  • 这几乎可以解决它...谢谢!您是否知道如何配置过滤器以解决“行包含空字节”错误?对于这种情况,我不太确定如何在 next 方法中触发错误
  • @NimishTodi :一旦设置了过滤器,就很容易适应它。查看我的编辑。
  • 您是否假设只是因为 utf-8 编解码器可以解码它,它是 utf-8 编码的?这是一个公平的假设吗?
  • @GreenAsJade 我已经发现了一个使用 Latin1 编辑器错误地编辑大型 utf8 编码 CSV 文件的案例。我没有手动浏览文件,而是使用了那种过滤器。对于 Latin1 中的法语语言,正确的重音字符序列被错误地识别为 utf8 的风险几乎为零。
猜你喜欢
  • 2011-06-27
  • 2015-02-17
  • 2012-01-29
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2019-11-28
  • 2020-01-14
  • 2014-04-16
相关资源
最近更新 更多