Лучший подход для определения разделителя CSV

Я видел несколько потоков о том, что лучшее решение для автоматического определения разделителя для входящего CSV. Большинство из них являются функциями длиной от 20 до 30 строк, с несколькими циклами, заранее определенным списком разделителей, чтением первых 5 строк и соответствием счетчиков e.t.c e.t.c

Вот 1 пример

Я только что реализовал эту процедуру с несколькими изменениями. Работает блестяще.

Затем я нашел следующий код:

private function DetectDelimiter($fh)
{
$data_1 = null;
$data_2 = null;
$delimiter = self::$delim_list['comma'];
foreach(self::$delim_list as $key=>$value)
{
$data_1 = fgetcsv($fh, 4096, $value);
$delimiter = sizeof($data_1) > sizeof($data_2) ? $key : $delimiter;
$data_2 = $data_1;
}

$this->SetDelimiter($delimiter);
return $delimiter;
}

Для меня это выглядит так, как будто достигается тот же результат, где $ delim_list представляет собой массив разделителей следующим образом:

static protected $delim_list = array('tab'=>"\t",
'semicolon'=>";",
'pipe'=>"|",
'comma'=>",");

Может ли кто-нибудь пролить свет на то, почему я не должен делать это так просто, и почему везде, куда бы я ни посмотрел, более запутанное решение кажется приемлемым ответом?

Спасибо!

7

Решение

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

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

a;b;c;d
a   b;  c   d
this|that;here|there
It's not ready, yet.; We have to wait for peter, paul, and mary.; They will know what to do

Хотя кажется, что это разделено точкой с запятой, ваш подход вернется comma,

3

Другие решения

Фиксированная версия.

В вашем коде, если строка содержит более 1 разделителя, вы получите неправильный результат (пример: val; строка с запятой; val2; val3). Также, если файл имеет 1 строку (количество строк < количество разделителей).

Вот исправленный вариант:

private function detectDelimiter($fh)
{
$delimiters = ["\t", ";", "|", ","];
$data_1 = null; $data_2 = null;
$delimiter = $delimiters[0];
foreach($delimiters as $d) {
$data_1 = fgetcsv($fh, 4096, $d);
if(sizeof($data_1) > sizeof($data_2)) {
$delimiter = sizeof($data_1) > sizeof($data_2) ? $d : $delimiter;
$data_2 = $data_1;
}
rewind($fh);
}

return $delimiter;
}
3

По вопросам рекламы [email protected]