将格式化字符串解析为数组的数组

发布于 2024-08-29 01:48:52 字数 696 浏览 8 评论 0原文

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

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

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

我可以使用爆炸轻松地将其分成几列,它给出了带有 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(...
+2-1+18*+7-21+3*-4-5+6x29

The above string is an example of the kind of string I'm trying to split into either a key => value array or something similar. The string is used to represent the layout of various classes on a three column page of an intranet site, which is editable by the user via drag and drop. This string is stored in a cookie to be used on the next visit.

The numbers represent the id of a class and -, + and x represent the state of the class (minimised, expanded or hidden), the * represents a column break.

I can split this into the columns easily using explode which gives and array with 3 $key => $value associations.

eg.

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

I then need to split this into the various classes from there, keeping the status and id together. As the different classes and statuses will change from user to user and how many there are for each column, I need to be able to do this all automatically.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

凉城已无爱 2024-09-05 01:48:52

首先 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));

But as PHP 不是 惰性语言,所有函数一遇到就会被求值,所以数组从 array_map 返回为:

array(2, 4, 9, 16)

在实际代码中,preg_match_all 返回一个匹配数组(其中匹配是数组)。因此,我所做的就是获取数组,并在每次匹配时应用一个函数,将匹配项转换为所需格式的不同数组。

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.

扶醉桌前 2024-09-05 01:48:52

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

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

代码: (Demo)

$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() 中的引用变量来实现。
  • 如果您不喜欢格式字符串中的重复,您可以将重复的子模式声明为变量,并以编程方式重复它(当然用星号分隔)。

Assuming that your strictly formatted input has a static number of segments and values per segment, there are some advantages to using sscanf() as a (verbose) direct way to parse the string instead of a preg_ technique.

  1. This is a direct single-function technique. No need to explode and then parse.
  2. There is no useless "fullstring match" generated by this function like preg_match() does.
  3. You don't need to pick out what you need from a $matches array (like with preg_match())
  4. The numeric values are already cast as integers (if that is useful to you).

Code: (Demo)

$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);

Output:

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,
  ),
)

p.s.

  • If you wanted the results to be a single array with 3 first-level elements and those elements containing 3 pairs of symbol-number subarrays, this is achievable as well by modifying the reference variables in sscanf().
  • If you don't like the repetition in the format string, you could declare the repeated subpattern as a variable and programmatically repeat it instead (delimited by asterisks of course).
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文