3
+2-1+18*+7-21+3*-4-5+6x29

上面的字符串是我尝试拆分为 key => value 数组或类似字符串的示例。该字符串用于表示内网站点三栏页面上各种类的布局,用户可以通过拖放对其进行编辑。此字符串存储在 cookie 中以供下次访问时使用。

数字代表类的 id 和,-代表类的状态(最小化、扩展或隐藏),代表分栏符。+x*

我可以使用explode轻松将其拆分为列,它给出了3个$key => $value关联的数组。

例如。

$column_layout = array( [0] => '+2-1+18' , [1] => '+7-21+3' , [2] => '-4-5+6x29' )

然后我需要从那里把它分成不同的类,把状态和id放在一起。由于不同的类和状态会因用户而异,以及每列有多少,我需要能够自动完成这一切。

$column1 = array(
    array( '+' , 2 ),
    array( '-' , 1 ),
    array( '+' , 18 )
);
$column2 = array(...
4

2 回答 2

7

首先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返回一个匹配数组(其中匹配是数组)。所以我所做的就是获取数组,并在每次匹配时应用一个函数,将匹配转换为所需格式的不同数组。

于 2010-04-19T12:35:02.647 回答
0

假设您严格格式化的输入具有静态数量的段和每个段的值,使用sscanf()(详细)直接方式来解析字符串而不是preg_技术有一些优势。

  1. 这是一种直接的单功能技术。无需爆炸然后解析。
  2. 这个函数不会像这样生成无用的“全字符串匹配” preg_match()
  3. 你不需要从$matches数组中挑选出你需要的东西(比如 with preg_match()
  4. 数值已经转换为整数(如果这对您有用)。

代码:(演示

$layout = '+2-1+18*+7-21+3*-4-5+6x29';

sscanf(
    $layout,
    '%[-+x]%d%[-+x]%d%[-+x]%d*%[-+x]%d%[-+x]%d%[-+x]%d*%[-+x]%d%[-+x]%d%[-+x]%d',
    $column1[0][0], $column1[0][1], $column1[1][0], $column1[1][1], $column1[2][0], $column1[2][1],
    $column2[0][0], $column2[0][1], $column2[1][0], $column2[1][1], $column2[2][0], $column2[2][1],
    $column3[0][0], $column3[0][1], $column3[1][0], $column3[1][1], $column3[2][0], $column3[2][1]
);

var_export($column1);
echo "\n---\n";
var_export($column2);
echo "\n---\n";
var_export($column3);

输出:

array (
  0 => 
  array (
    0 => '+',
    1 => 2,
  ),
  1 => 
  array (
    0 => '-',
    1 => 1,
  ),
  2 => 
  array (
    0 => '+',
    1 => 18,
  ),
)
---
array (
  0 => 
  array (
    0 => '+',
    1 => 7,
  ),
  1 => 
  array (
    0 => '-',
    1 => 21,
  ),
  2 => 
  array (
    0 => '+',
    1 => 3,
  ),
)
---
array (
  0 => 
  array (
    0 => '-',
    1 => 4,
  ),
  1 => 
  array (
    0 => '-',
    1 => 5,
  ),
  2 => 
  array (
    0 => '+',
    1 => 6,
  ),
)

ps

  • 如果您希望结果是具有 3 个第一级元素的单个数组,并且这些元素包含 3 对符号数子数组,这也可以通过修改 中的参考变量来实现sscanf()
  • 如果您不喜欢格式字符串中的重复,您可以将重复的子模式声明为变量并以编程方式重复它(当然由星号分隔)。
于 2021-08-10T22:04:35.677 回答