Преобразование совпадений регулярного выражения в многомерный массив

Правильный код ниже:

  • letter 'c' followed by digit
  • letter 'c' followed by digit dash digit
  • digit may be followed by an other digit enclosed in square parentheses []

и создает массив, как ожидалось:

 Array ( [0] => Array ( [start] => 4 [end]=> 8 ) [1] => Array ( [start] => 2 [end]=> ) [2] => Array ( [start] => 3 [end] => 5 ) [3] => Array ( [start] => 6[2] [end] => ) [4] => Array ( [start] => 8[4] [end] => 10 ) [5] => Array ( [start] => 14 [end] => 21[5] ) ) 

КОД:

  $str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]"; $re = "~c(?<start>\d+(?:\[\d+])?)(?:-(?<end>(?&start)?))?~"; $myarray = explode("|",$str); foreach ($myarray as $my) { preg_match_all($re, $my, $matches); $res = array_map(function($ms, $me) { return array("start" => $ms, "end" => $me); }, $matches["start"], $matches["end"]); } echo "<pre>"; print_r($res); echo "</pre>"; 

Теперь я хотел бы добавить другой key со значением цифры после a . Так, например, учитывая приведенную выше $str

 $str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]". 

значения a : 2 и 6 а ожидаемый массив результатов будет следующим. Обратите внимание, что 6 повторяется для каждого c .

 Array ( [0] => Array ( [a] => 2 [start] => 4 [end]=> 8 ) [1] => Array ( [a] => 6 [start] => 2 [end]=> ) [2] => Array ( [a] => 6 [start] => 3 [end] => 5 ) [3] => Array ( [a] => 6 [start] => 6[2] [end] => ) [4] => Array ( [a] => 6 [start] => 8[4] [end] => 10 ) [5] => Array ( [a] => 6 [start] => 14 [end] => 21[5] ) ) 

Вы можете сделать это:

 $str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]"; $re = '~(?:a(?<a>\d+))?c(?<start>\d+(?:\[\d+])?)(?:-(?<end>\g<start>))?~'; if (preg_match_all($re, $str, $matches, PREG_SET_ORDER) ) { $a = ''; // current value for "a" -----, $result = array_map(function ($i) use (&$a) { if (!empty($i['a'])) $a = $i['a']; else $i['a'] = $a; if (!isset($i['end'])) $i['end'] = ''; foreach ($i as $k=>$v) { if (is_numeric($k)) unset($i[$k]); } return $i; }, $matches); } print_r($result); 

Но если вы уже точно знаете, как выглядит строковый формат, и если вам не нужно его проверять, возможно, есть более умные (и более быстрые) способы получить тот же результат.

Например, используя explode и форматированные строки с помощью sscanf :

 $str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]"; $parts = explode('|', $str); $result = []; $keys = ['a', 'start', 'end']; foreach($parts as $part) { foreach(explode(',', $part) as $k=>$v) { if ($k) list($start, $end) = sscanf($v, 'c%[^-]-%[^,]'); else list($a, $start, $end) = sscanf($v, 'a%dc%[^-]-%[^,]'); $result[] = array_combine($keys, [$a, $start, $end]); } } print_r($result);