Reputation: 4377
The code below correctly matches:
letter 'c' followed by digit
letter 'c' followed by digit dash digit
digit may be followed by an other digit enclosed in square parentheses []
and creates an array as expected as this:
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]
)
)
CODE:
$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>";
Now I would like to add an other key
with the value of the digit after the a
.
So for example, given the above $str
$str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]".
the a
values are: 2
and 6
and the expected result array would be the following. Note that 6
is repeated for every c
matched.
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]
)
)
Upvotes: 0
Views: 73
Reputation: 89557
You can do that:
$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);
But if you already know exactly how is the string format and if you don't need to validate it, there are probably smarter (and faster) ways to obtain the same result.
For example, using explode
and formatted strings with 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);
Upvotes: 1