CSV Autodetection в Java

Каким будет надежный способ автоматического определения того, что файл является фактически CSV, если CSV было переопределено, чтобы означать "значения, разделенные символами", то есть данные с использованием любого отдельного символа (но обычно любые не- буквенно-цифровой символ) как разделитель, а не только запятые?

По существу, с этим (re) определением CSV = DSV ( "Разделяемые разделителем значения" ), обсуждаемые, например, в этом Статья в Википедии, тогда как формат "Comma Separated Values ​​" определен в RFC 4180.

В частности, существует ли метод статистического вычитания того, что данные имеют как-то "фиксированную" длину, что означает "возможный CSV"? Простое подсчет количества разделителей не всегда работает, потому что есть CSV файлы с переменными числами полей на запись (т.е. Записи, которые, напротив, соответствуют мандатам RFC 4180, не имеют одинакового числа поля в одном файле).

Распознавание CSV представляется особенно сложной задачей, особенно если обнаружение не может основываться на расширении файла (например, при чтении потока, который не имеет такой информации).

Для правильного ( "полного" ) автоматического определения требуется не менее 4 решений:

  • Обнаружение того, что файл на самом деле является CSV
  • Обнаружение наличия заголовков
  • Обнаружение фактического символа разделителя
  • Обнаружение специальных символов (например, кавычек)

Полное автоопределение, кажется, не имеет единого решения из-за сходства других наборов данных (например, свободного текста, который использует запятые), особенно для таких угловых случаев, как записи переменной длины, одинарные или двойные кавычки, или многострочные записи.

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

Даже коммерческие приложения, такие как Excel, полагаются на расширение файла (.csv), чтобы решить (1), что, очевидно, не является автоопределением, хотя проблема значительно упрощена, если в заявлении говорится, что данные являются CSV.

Вот некоторые хорошие статьи, посвященные эвристике для (2) и (3):

Обнаружение (4), тип кавычек, может быть основано на обработке нескольких строк из файла и поиске соответствующих значений (например, четное число "или" для каждой строки будет означать одиночные или двойные кавычки) Такая обработка может быть выполнена путем инициализации существующего анализатора CSV (например, OpenCSV), который будет должным образом учитывать разделение строк CSV (например, многострочные события).

Но как насчет (1), т.е. решая, что данные CSV в первую очередь?

Помогла ли интеллектуальная обработка данных помощь в этом решении?

Ответ 1

Если вы не можете ограничить использование разделителя, вы можете использовать грубую силу.

Вы можете перебирать все возможные комбинации символов кавычки, разделителя столбцов и разделителя записей (256 * 255 * 254 = 16581120 для ASCII).

id,text,date
1,"Bob says, ""hi
..."", with a sigh",1/1/2012

Удалить все цитируемые столбцы, это можно сделать с заменой RegEx.

//quick javascript example of the regex, you'd replace the quote char with whichever character your currently testing
var test='id,text,date\n1,"bob, ""hi\n..."", sigh",1/1/2011';
console.log(test.replace(/"(""|.|\n|\r)*?"/gm,""));

id,text,date
1,,1/1/2012

Разделить на разделитель записей

["id,text,date", "1,,1/1/2012"]

Разделить записи по разделителю столбцов

[ ["id", "text", "date"], ["1", "", "1/1/2012"] ]

Если количество столбцов на запись соответствует определенному значению CSV.

3 == 3

Если количество столбцов не соответствует, попробуйте использовать другую комбинацию символов строки, столбца и кавычки

ИЗМЕНИТЬ

Фактически анализируя данные после уверенности в разделителях, и проверка однородности столбцов может быть полезным дополнительным шагом

  • Все столбцы в строках строк первого (заголовка?)
  • Столбец X всегда анализирует значение null/empty или valid (int, float, date)

Чем больше CSV-данных (строк, столбцов) нужно работать, тем больше уверенности вы можете извлечь из этого метода.

Я думаю, что этот вопрос выглядит глупым/чрезмерно общим, если у вас есть поток неизвестных данных, которые вы обязательно захотите проверить во всех "низко висящих фруктах". Бинарные форматы обычно имеют довольно четкие заголовки подписей, а затем XML и JSON для легко обнаруживаемых текстовых форматов.

Ответ 2

Всегда будут файлы, отличные от CSV, которые выглядят как CSV, и наоборот. Например, есть патологический (но вполне достоверный) CSV файл, который frankc размещен в цитируемой Java-ссылке:

Name
Jim
Tom
Bill

Лучшее, что может сделать, я думаю, это какая-то эвристическая оценка вероятности того, что файл CSV. Некоторые эвристики, о которых я могу думать, следующие:

  • Существует символ разделителя-кандидата, который появляется в каждой строке (или, если хотите, каждая строка имеет один токен).
  • Учитывая символ разделителя-кандидата, большинство (но не обязательно всех) строк имеют одинаковое количество полей.
  • Наличие первой строки, которая выглядит как заголовок, повышает вероятность файла, содержащего CSV-данные.

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