首先explode()是带有分隔符的数组*
然后,您可以使用 preg_match_all 匹配展开数组中的每个项目。像这样的东西适用于您的示例输入。
$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;
}
您的示例的输出结果如下:
array(
     array( array('+', '2'), array('-', '1'), array('+', '18') ),
     array( array('+', '7'), array('-', '21'), array('+', '3') ),
     //etc
);
使用 PHP 5.3,您可以使用类似的东西(未经测试)。主要区别在于内部循环已被替换array_map为无需大量代码行。(数组映射将函数应用于数组中的每个项目并返回转换后的数组)。漂亮的闭包语法需要 PHP 5.3
$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);
}
您还可以完全删除循环:
$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));
然而,这对大多数 PHP 开发人员来说有一个很大的缺点,那就是不推荐使用它。
更多解释
应@Christopher Altman的要求
PHP 5.3 版本中唯一的新特性是:
array_map(
          function($a){ return array($a[1], $a[2]); },
          $matches
);
稍微扩展和改变它(例如)
//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);
所以如果$myArray定义为
array(1,2,3,4);
当它通过数组映射函数运行时,您可以将其视为将其转换为
array(func(1),func(2),func(3),func(4));
但由于 PHP 不是一种惰性语言,所有函数在遇到时都会立即求值,因此数组从 array_map 返回为:
array(2, 4, 9, 16)
在实际代码中,preg_match_all返回一个匹配数组(其中匹配是数组)。所以我所做的就是获取数组,并在每次匹配时应用一个函数,将匹配转换为所需格式的不同数组。