Расщепление точкой с запятой, не окруженное кавычками

Ну, привет, сообщество. Я работаю над декодером CSV на PHP (да, я знаю, что он уже есть, но для меня это вызов, так как я изучаю его в свободное время). Теперь проблема: ну, строки разделены на PHP_EOL,

В этой строке:

foreach(explode($sep, $str) as $line) {

где сентябрь переменная, которая разделяет строки и ул Строка, которую я хочу расшифровать.

Но если я хочу разделить столбцы точкой с запятой, может возникнуть ситуация, когда точка с запятой — это содержимое одного столбца. И, как я исследовал, эта проблема решается путем окружения всего столбца кавычками:

Входные данные:

"0;0";1;2;3;4

Ожидаемый результат:

0; 0 | 1 | 2 | 3 | 4

Я уже думал о взгляде вперед / назад. Но так как я не использовал его в прошлом, и, возможно, это может быть хорошей практикой, я не знаю, как включить его в регулярное выражение. Моя функция декодирования возвращает 2D-массив (например, таблицу …), и я подумал добавить строки в массив следующим образом (Да, регулярное выражение f *** ed …):

$res[] = preg_split("/(?<!\")". preg_quote($delim). "(?!\")/", $line);

И наконец мой полный код:

function csv_decode($str, $delim = ";", $sep = PHP_EOL) {
if($delim == "\"") $delim = ";";
$res = [];

foreach(explode($sep, $str) as $line) {
$res[] = preg_split("/(?<!\")". preg_quote($delim). "(?!\")/", $line);
}

return $res;
}

Заранее спасибо!

1

Решение

Это немного нелогично, но самый простой способ разбить строку с помощью регулярных выражений — это часто использовать preg_match_all на месте preg_split:

preg_match_all('~("[^"]*"|[^;"]*)(?:;|$)~A', $line, $m);
$res[] = $m[1];

Модификатор A обеспечивает непрерывность последовательных совпадений с начала строки.

Если вы не хотите, чтобы цитаты были включены в результат, вы можете использовать функция сброса ветви (?|..(..)..|..(..)..):

preg_match_all('~(?|"([^"]*)"|([^;"]*))(?:;|$)~A', $line, $m);

Другой обходной путь, но на этот раз для preg_split: включите часть, которую вы хотите избежать, перед разделителем и отбросьте ее из всего соответствия, используя \K особенность:

$res[] = preg_split('~(?:"[^"]*")?\K;~', $line);
2

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

Вы можете использовать эту функцию str_getcsv в этом вы можете указать пользовательский разделитель (;) также.

Попробуйте этот фрагмент кода

<?php

$string='"0;0";1;2;3;4';
print_r(str_getcsv($string,";"));

Выход:

Array
(
[0] => 0;0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
)
1

Разделение не является хорошим выбором для линий типа CSV.
Вы могли бы использовать старый проверенный и верный \G якорь с находкой глобально типа func.

практический

Regex: '~\G(?:(?:^|;)\s*)(?|"([^"]*)"|([^;]*?))(?:\s*(?:(?=;)|$))~'

Информация:

 \G                            # G anchor, start where last match left off
(?:                           # leading BOL or ;
(?: ^ | ; )
\s*                           # optional whitespaces
)
(?|                           # branch reset
"( [^"]* )                     # (1), double quoted string data
"|                              # or
( [^;]*? )                    # (1), non-quoted field
)
(?:                           # trailing optional whitespaces
\s*
(?:
(?= ; )                       # lookahead for ;
|  $                             # or EOL
)
)
0
По вопросам рекламы [email protected]