你能跳过python csv中的非utf-8数据吗?

时间:2015-05-15 15:34:12

标签: python csv utf-8

我在python中处理一个非常大的csv文件,其中一些行抛出错误“'utf-8'编解码器无法解码位置7657中的字节0x9b:无效的起始字节”。有没有办法在不手动删除或修复数据的情况下跳过不是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

1 个答案:

答案 0 :(得分:1)

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

  • 如果成功,则将其传递给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)