First explode()
the array with the delimiter *
You could then use preg_match_all to match each item in the exploded array. Something like this works with your example input.
$layout = explode('*', $input);
$columns = array();
foreach ( $layout as $item ){
$parts = array();
//matches either a -, x or + followed by one or more digits
preg_match_all('/([+-x])(\d+)/', $item, $matches, PREG_SET_ORDER);
foreach ( $matches as $match){
//match[1] hold the + or -, match[2] holds the digits
$parts[] = array($match[1], $match[2]);
}
$columns[] = $parts;
}
The output from your example ends up like this:
array(
array( array('+', '2'), array('-', '1'), array('+', '18') ),
array( array('+', '7'), array('-', '21'), array('+', '3') ),
//etc
);
With PHP 5.3 you could use something like this (untested). The main difference is that the inner loop has been replaced by array_map
which removes the need for a lot of lines of code. (Array map applies a function to every item in an array and returns the transformed array). PHP 5.3 is required for the nice closure syntax
$layout = explode('*', $input);
$columns = array();
foreach ( $layout as $item ){
preg_match_all('/([+-x])(\d+)/', $item, $matches, PREG_SET_ORDER);
$columns[] = array_map( function($a){ return array($a[1], $a[2]); },
$matches);
}
You could also remove the loops altogether:
$innerMatch = function($item){
preg_match_all('/([+-x])(\d+)/', $item, $matches, PREG_SET_ORDER);
return array_map( function($a){ return array($a[1], $a[2]); },
$matches);
};
$columns = array_map($innerMatch, explode('*', $input));
However this has the large disadvantage of not being very readable to most PHP developers which is why I wouldn't recommend using it.
More explanation
At the request of @Christopher Altman
The only new bit in the PHP 5.3 version is really this:
array_map(
function($a){ return array($a[1], $a[2]); },
$matches
);
Expanding and altering it a bit (as an example)
//bind an anonymous function to the variable $func
$func = function($a){
return $a*$a;
};
//$func() now calls the anonymous function we have just defined
//then we can call it like so:
$result = array_map($func, $myArray);
So if $myArray
is defined as
array(1,2,3,4);
When it is run through the array map function you can think of it as converting it into
array(func(1),func(2),func(3),func(4));
But as PHP isn't a lazy language, all the functions are evaluated as soon as they are encountered, so the array is returned from array_map as:
array(2, 4, 9, 16)
In the actual code, preg_match_all
returns an array of matches (where the matches are arrays). So all I do is take the array and on every match apply a function that converts the match into a different array in the required format.