Регулярное выражение: сопоставление ',' после нуля или нечетного вхождения двойной кавычки

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

Полностью игнорируя последнее предложение, я решил изменить саму проблему на следующую:

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

Пример:

text,"some,"chars,chars"more,""text",
    *     x      *          x       *

Где * - совпадения, а x - нет.

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

2 ответа

Решение

Я уверен, что это может быть написано намного лучше, но вот вариант, который работает для вашего случая:

 preg_match_all('/
     \s* ((?: (?=.|(?<=,)$) [^",]* | "(?: ""|[^"]* )+" )+) \s* (?:,|$) /xms',
     $line, $matches
 )
 and print_r($matches[1]);

Но это не соблюдает другие типичные правила CSV. Я бы обычно ожидал \" чтобы избежать двойных кавычек внутри. И смешанные кавычки и не заключенные в кавычки подстроки также очень нестандартны. И в ней отсутствует какая-либо форма проверки, поэтому она просто пропустит любую последнюю цитату - что угодно, если не правильно спарено.

Для вашей тестовой строки:

        [0] => text
        [1] => "some,"chars
        [2] => chars"more,""text"
        [3] => 

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

$csvString = 'zero,"o,ne",two,"thr,ee"';

function parseCsv($string, &$result)
{
    $regex = '/^((".*")|([^"].*))(,(.*))?$/U';
    $matches = array();
    preg_match($regex, $string, $matches);
    $result[] = $matches[1];
    if(isset($matches[5]))
    {
        parseCsv($matches[5], $result);
    }
}

$result = array();
parseCsv($csvString, $result);

var_dump($result);

Обратите внимание, что это не было проверено со строками в кавычках, которые содержат (экранированные) кавычки. Также он содержит кавычки вокруг строк в кавычках.

Результатом вышеупомянутой функции является

array
  0 => string 'zero' (length=4)
  1 => string '"o,ne"' (length=6)
  2 => string 'two' (length=3)
  3 => string '"thr,ee"' (length=8)
Другие вопросы по тегам