Напишите алгоритм парсинга CSV файла с неизвестным сепаратором
Что проверяют
Знаете ли вы стандартную библиотеку и понимаете ли, что CSV не разбирается делением строки по символу. Кавычки, экранирование, переводы строк внутри поля и кодировка выгрузки это и есть содержание вопроса.
Как отвечать
В модуле csv для этого есть Sniffer, который анализирует образец и возвращает диалект целиком, включая символ кавычек:
import csv
def read_csv(path):
with open(path, newline="", encoding="utf-8-sig") as f:
sample = f.read(8192)
f.seek(0)
try:
dialect = csv.Sniffer().sniff(sample, delimiters=",;\t|")
except csv.Error:
dialect = csv.excel
return list(csv.reader(f, dialect))Обязательно объясните две детали: newline="" нужен, чтобы модуль сам разбирал переводы строк внутри закавыченных полей, а utf-8-sig снимает BOM, который иначе приклеится к первой колонке заголовка. Если Sniffer не справился, честный запасной вариант считает не частоту символов, а стабильность числа колонок: настоящий разделитель даёт одинаковую длину строки на всём образце. Уместно упомянуть pandas.read_csv с sep=None, который внутри зовёт тот же Sniffer.
Где спотыкаются
Выбирают разделитель по максимальному числу вхождений. В файле, где описания заполнены запятыми или точками с запятой, победит символ из данных, а не настоящий разделитель, и разбор развалится на первой же длинной строке.
Открывают файл без newline="" и наугад по кодировке. Windows-1251 и BOM это два самых частых сюрприза в выгрузках из офисных программ, а определение кодировки по первой тысяче байт уверенно ошибается на коротких файлах с латиницей в начале.
Пишут line.split(sep) вместо модуля. Такой разбор ломается на закавыченном поле с разделителем внутри, на удвоенных кавычках, означающих одну кавычку в значении, и на пустой последней строке файла, которая превращается в лишнюю запись.