Цикл над файлом .csv и удаление любых строк, не относящихся к ascii - PullRequest
0 голосов
/ 17 мая 2018

У меня есть файл .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 голосов
/ 17 мая 2018

Проблема в том, что вы не знаете, какие кодировки используются для писем, не относящихся к 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, и, кроме того, все, что вы делаете, это пишете целую строку байтов сразу), так что все будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...