Я видел несколько потоков о том, что лучшее решение для автоматического определения разделителя для входящего CSV. Большинство из них являются функциями длиной от 20 до 30 строк, с несколькими циклами, заранее определенным списком разделителей, чтением первых 5 строк и соответствием счетчиков e.t.c e.t.c
Я только что реализовал эту процедуру с несколькими изменениями. Работает блестяще.
Затем я нашел следующий код:
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'=>",");
Может ли кто-нибудь пролить свет на то, почему я не должен делать это так просто, и почему везде, куда бы я ни посмотрел, более запутанное решение кажется приемлемым ответом?
Спасибо!
Как правило, вы не можете обнаружить разделитель для текстового файла. Если есть дополнительные подсказки, вы должны быть уверены, что внедрили их в свое обнаружение.
Особая проблема с предлагаемым подходом состоит в том, что он будет подсчитывать количество элементов в разных строках файла. Предположим, у вас был такой файл:
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
,
Фиксированная версия.
В вашем коде, если строка содержит более 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;
}