2012-06-16 3 views
2

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

'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" 
} 

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

+1

вам нужно preg_split .... – dynamic

+1

Как вы описали, ваш вопрос сводится к тому, «Я хочу, чтобы разделить эту строку с помощью магии, так как для меня, как человеческого существа, очевидно, что запятая в скобках не должен расколоть его ». Вы должны определить критерии разделения лучше, чем этот единственный пример. – lanzz

+0

См. Мое редактирование @lanzz. – Donovan

ответ

5

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

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

Это работает очень, очень хорошо. Спасибо. – Donovan

+1

Теперь с повышением уровня: что, если $ a есть «(a) b, c»?:-) Первые скобки пропускаются. – Donovan

+0

(см. Измененную версию выше) – disjunction

1

Этот фрагмент кода помогает мне с вложенной скобкой. В принципе идея заключается в том, чтобы рекурсивно заменить (*) на некоторый идентификатор, пока не будет больше круглых скобок. Затем взорвите строку запятой, а затем положите все обратно. Это не идеальное решение - сделано это сейчас примерно за 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) 

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

0

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

Код: (Demo)

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

Выход:

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

Pattern Demo

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