0

Можно ли импортировать CSV-файл и автоматически определить разделитель?

14

У меня есть задача по импорту двух типов CSV-файлов: некоторые используют разделитель ";", другие — ",". В настоящее время я переключаюсь между следующими двумя строками кода:

reader = csv.reader(f, delimiter=';')

или

reader = csv.reader(f, delimiter=',')

Есть ли возможность не указывать разделитель и позволить программе автоматически определять правильный разделитель?

Решения, предложенные ниже (Blender и sharth), кажутся работающими хорошо для файлов с запятой (генерируемых с помощью LibreOffice), но не подходят для файлов с точкой с запятой (созданных в MS Office). Вот первые строки одного из файлов с разделителем ";":

ReleveAnnee;ReleveMois;NoOrdre;TitreRMC;AdopCSRegleVote;AdopCSAbs;AdoptCSContre;NoCELEX;ProposAnnee;ProposChrono;ProposOrigine;NoUniqueAnnee;NoUniqueType;NoUniqueChrono;PropoSplittee;Suite2LecturePE;Council PATH;Notes
1999;1;1;1999/83/EC: Council Decision of 18 January 1999 authorising the Kingdom of Denmark to apply or to continue to apply reductions in, or exemptions from, excise duties on certain mineral oils used for specific purposes, in accordance with the procedure provided for in Article 8(4) of Directive 92/81/EEC;U;;;31999D0083;1998;577;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document
1999;1;2;1999/81/EC: Council Decision of 18 January 1999 authorising the Kingdom of Spain to apply a measure derogating from Articles 2 and 28a(1) of the Sixth Directive (77/388/EEC) on the harmonisation of the laws of the Member States relating to turnover taxes;U;;;31999D0081;1998;184;COM;NULL;CS;NULL;;;;Propos* are missing on Celex document

Как можно решить эту проблему и добиться корректной работы с обоими форматами?

4 ответ(ов)

0

Ваше наблюдение абсолютно верно. Метод csv.Sniffer().sniff() действительно использует эвристики для определения разделителя, и иногда он может не справляться с файлами, в которых строки имеют разное количество разделителей, особенно если используются несколько символов-разделителей, таких как запятая и вертикальная черта.

Попробовав прочитать всего две строки файла, вы увеличили шансы корректного определения разделителя. Это связано с тем, что csv.Sniffer получает более полное представление о структуре файла. При этом, если в файле строки сформированы неравномерно, у вас больше шансов на успех.

Ваш подход имеет смысл, и его можно рекомендовать тем, кто работает с CSV-файлами с различными разделителями. Также не забудьте учитывать ситуацию с кавычками, как вы и упомянули, так как это может влиять на результат.

Вот ваш исправленный пример кода для ясности:

import csv

with open('file.csv', 'r') as csvfile:
    temp_lines = csvfile.readline() + '\n' + csvfile.readline()
    dialect = csv.Sniffer().sniff(temp_lines, delimiters=',|')

Так вы сможете более эффективно определить разделитель. Отличная работа!

0

Для решения данной задачи я создал функцию, которая считывает первую строку файла (заголовок) и определяет разделитель.

def detectDelimiter(csvFile):
    with open(csvFile, 'r') as myCsvfile:
        header = myCsvfile.readline()
        if header.find(";") != -1:
            return ";"
        if header.find(",") != -1:
            return ","
    # стандартный разделитель (экспорт из MS Office)
    return ";"

Эта функция открывает указанный CSV-файл, читает первую строку и проверяет, содержится ли в ней символ ; или ,. Если находит ;, возвращает его как разделитель; если находит ,, возвращает его. Если ни один из символов не найден, функция возвращает ; как значение по умолчанию, предполагая, что файл экспортирован из MS Office.

0

Если вы используете DictReader, то можете сделать это следующим образом:

#!/usr/bin/env python
import csv

def parse(filename):
    with open(filename, 'rb') as csvfile:
        dialect = csv.Sniffer().sniff(csvfile.read(), delimiters=';,')
        csvfile.seek(0)
        reader = csv.DictReader(csvfile, dialect=dialect)

        for line in reader:
            print(line['ReleveAnnee'])

Я использовал этот код с Python 3.5, и он работал таким образом.

0

Я не думаю, что может быть абсолютно универсальное решение для этой задачи. Например, одной из причин, почему я могу использовать , в качестве разделителя, является то, что некоторые из моих полей данных должны включать ;. Простая эвристика для определения разделителя может заключаться в том, чтобы просто прочитать первую строку (или несколько строк), посчитать, сколько символов , и ; в них содержится (возможно, игнорируя те, что находятся внутри кавычек, если программа, создающая ваши .csv файлы, корректно и последовательно экранирует записи), и предположить, что более частый из них является правильным разделителем.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь