Разбить сложную строку запятыми в PHP

Мне нужно разбить строку, содержащую запятые. Я уже нашел что-то для строк вроде str_getcsv :

 'A', 'B with a comma, eh', 'C' 

Но моя строка такая, например, без каких-либо символов для значений:

 A, B (one, two), C 

Мне нужно взорвать это и получить:

 array(3) { [0]=> string(1) "A" [1]=> string(12) "B (one, two)" [2]=> string(1) "C" } 

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

Solutions Collecting From Web of "Разбить сложную строку запятыми в PHP"

Но есть решение для вашего безумного желания;)

 $a = "(Z) X, (Y, W) A, B (one, two), C, D (E,F,G) H, IJ"; $reg = '/[^(,]*(?:\([^)]+\))?[^),]*/'; preg_match_all($reg, $a, $matches); $result = array_filter($matches[0]); var_dump($result); 

Этот фрагмент помогает мне с вложенными скобками. В принципе идея заключается в том, чтобы рекурсивно заменить (*) на некоторый идентификатор, пока не будет больше круглых скобок. Затем взорвите строку запятой, а затем положите все обратно. Это не идеальное решение – сделало его сейчас примерно за 30 минут, но оно работает 🙂 Это определенно можно как-то оптимизировать.

 /** * Explode string by delimiter, but don't explode if delimiter is inside parenthesis. * This also support nested parenthesis - that's where pure RegExp solutions fails. * * For example, * $input = "one, two three, four (five, (six, seven), (eight)) (nine, ten), eleven"; * $output = array( * 'one', * 'two three', * 'four (five, (six, seven), (eight)) (nine, ten)', * 'eleven' * ); * * @param string $input * @param string $delimiter = , * @param string $open_tag = \( * @param string $close_tag = \) * @return array */ function exploder($input, $delimiter = ',', $open_tag = '\(', $close_tag = '\)') { // this will match any text inside parenthesis // including parenthesis itself and without nested parenthesis $regexp = '/'.$open_tag.'[^'.$open_tag.$close_tag.']*'.$close_tag.'/'; // put in placeholders like {{\d}}. They can be nested. $r = array(); while (preg_match_all($regexp, $input, $matches)) { if ($matches[0]) { foreach ($matches[0] as $match) { $r[] = $match; $input = str_replace($match, '{{'.count($r).'}}', $input); } } else { break; } } $output = array_map('trim', explode($delimiter, $input)); // put everything back foreach ($output as &$a) { while (preg_match('/{{(\d+)}}/', $a, $matches)) { $a = str_replace($matches[0], $r[$matches[1] - 1], $a); } } return $output; } $a = "one, two three, four (five, (six, seven), (eight)) (nine, ten), eleven"; var_dump(exploder($a)); 

Это приведет к выводу:

 array (size=4) 0 => string 'one' (length=3) 1 => string 'two three' (length=9) 2 => string 'four (five, (six, seven), (eight)) (nine, ten)' (length=46) 3 => &string 'eleven' (length=6) 

как и ожидалось.

Более элегантно, чем создание массива, а затем фильтрация результатов, вы можете использовать preg_split() в этой preg_split() однострочной линии:

Код: ( Демо )

 $string='A, B (one, two), C'; var_export(preg_split('/(?:\([^)]*\)(*SKIP)(*FAIL))|, /',$string)); 

Вывод:

 array ( 0 => 'A', 1 => 'B (one, two)', 2 => 'C', ) 

Демо-версия шаблона

  • (*SKIP)(*FAIL) – это метод, который дисквалифицирует подстроки перед сопоставлением.
  • Отрицательный класс символов [^)]* является более быстрой альтернативой . (Точка). * если у вас есть вложенные выражения в скобках, этот шаблон не будет работать … запись шаблона для этого сценария немного выходит за рамки этого вопроса.