Я пытаюсь проанализировать ряд данных CSV с помощью PHP, но имея главную проблему. Одно из полей является длинным полем описания, которое самим содержит разрывы строки в корпусах.
Моя основная проблема пишет часть кода, который может разделить данные линию за линией, но также и распознать, когда разрывы строки в данных не должны использоваться. Разрывов строки в этом поле правильно не оставляют, делая их трудно для различения от законных разрывов строки.
Я попытался придумать регулярное выражение, которое может правильно обработать его, но не имело никакой удачи до сих пор. Какие-либо идеи?
Формат CSV:
"####","text data here", "text data \n with linebreaks \n here"\n
"####","more text data", "more data \n with \n linebreaks \n here"\n
По словам Алеске, комментатора в документации для функции PHP fgetcsv :
Обработка файлов CSV в PHP нестандартна и противоречит RFC4180, таким образом, fgetcsv ( ) не может правильно работать с файлами [которые содержат разрывы строк] ...
И он предложил следующую функцию, чтобы обойти это ограничение:
function csvstring_to_array(&$string, $CSV_SEPARATOR = ';', $CSV_ENCLOSURE = '"', $CSV_LINEBREAK = "\n") {
$o = array();
$cnt = strlen($string);
$esc = false;
$escesc = false;
$num = 0;
$i = 0;
while ($i < $cnt) {
$s = $string[$i];
if ($s == $CSV_LINEBREAK) {
if ($esc) {
$o[$num] .= $s;
} else {
$i++;
break;
}
} elseif ($s == $CSV_SEPARATOR) {
if ($esc) {
$o[$num] .= $s;
} else {
$num++;
$esc = false;
$escesc = false;
}
} elseif ($s == $CSV_ENCLOSURE) {
if ($escesc) {
$o[$num] .= $CSV_ENCLOSURE;
$escesc = false;
}
if ($esc) {
$esc = false;
$escesc = true;
} else {
$esc = true;
$escesc = false;
}
} else {
if ($escesc) {
$o[$num] .= $CSV_ENCLOSURE;
$escesc = false;
}
$o[$num] .= $s;
}
$i++;
}
// $string = substr($string, $i);
return $o;
}
Похоже, это поможет.
В итоге я смог изменить регулярное выражение с помощью определенных специальных флагов, чтобы они работали для моих нужд. Я использовал следующий вызов функции:
preg_match_all('/"\d+",".*",".*"\n/sU', $csv_data, $matches);
Кажется, это работает по нескольким причинам:
1) Флаг 's' указывает редактору перехватывать новые строки под точкой, что обычно не так. Прискорбный побочный эффект этого заключается в том, что допустимые символы новой строки также перехватываются точкой, что теоретически может привести весь CSV к одному результату, поэтому
2) я добавил флаг U. Это говорит о том, что точка по умолчанию не является жадной, и поэтому в настоящее время она соответствует только одной строке за кусок.
Для синтаксического анализа csv можно использовать fgetcsv или strgetcsv . Посмотрите примеры в документации php.