循环.csv文件并删除任何非ascii字符串

时间:2018-05-17 18:24:54

标签: python loops

我有一个包含大量电子邮件的.csv文件,每个电子邮件都在一个单独的行上。我试图删除任何包含非ascii字符的电子邮件。这就是我想要的:

def is_ascii(s):
    return all(ord(c) < 128 for c in s)


if __name__ == "__main__":

    with open('emails.csv') as csv_file:
        for line in csv_file:
            if(is_ascii(line)):
                with open('result.csv', 'a') as output_file:
                    output_file.write(line)

它一直给我一个错误:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 5012: invalid start byte

1 个答案:

答案 0 :(得分:0)

问题是你不知道非ASCII电子邮件的编码是什么,所以你只想跳过它们。

但您的代码正在尝试使用默认编码对其进行解码,然后决定是否跳过它们。这就是在文本模式下打开文件的意思,如下所示:

with open('emails.csv') as csv_file:
    for line in csv_file:

由于默认编码是UTF-8,因此只要遇到某些其他不兼容UTF-8的字符集编码的内容,就会出错。

将此更改为最简单的方法是以二进制模式打开文件。然后你只能解码你决定保留的行:

with open('emails.csv', 'rb') as csv_file:
    for line in csv_file:
        if(is_ascii(line)):
            line = line.decode('ascii')
            with open('result.csv', 'a') as output_file:
                output_file.write(line)

...或者只是通过以二进制模式打开输出文件来保持整个字节:

with open('emails.csv', 'rb') as csv_file:
    for line in csv_file:
        if(is_ascii(line)):
            with open('result.csv', 'ab') as output_file:
                output_file.write(line)

无论哪种方式,您都必须更改isascii函数,因为bytes是一个0-255的整数序列,而不是一系列字符,所以你不能(和不需要)致电ord

def is_ascii(s):
    return all(c < 128 for c in s)

存在潜在问题。我认为你会好的,但你应该考虑一下(并测试你需要测试的任何东西)。虽然文本模式文件对象自动处理非Unix换行符,但二进制模式文件却没有。

如果您以某种方式拥有上个世纪的经典Mac(pre-OS X)文件,并且\r结尾,则您的代码将无效。 \r根本不会被视为换行符,因此整个文件看起来就像一条巨大的行。如果您不希望有任何此类文件,我不会担心。

但是如果您拥有的唯一非Unix文件是Windows(或DOS),\r\n,那么你会没事的。 \r将被视为行的一部分而不是换行的一部分,但这对您的代码(ord('\r') < 128无关紧要,除此之外,您所做的只是编写整个行一次性的字节行数),所以事情就会起作用。