【问题标题】:Convert the matches of a regex into a multidimensional array将正则表达式的匹配项转换为多维数组
【发布时间】:2016-06-22 13:01:03
【问题描述】:

下面的代码正确匹配:

  • letter 'c' followed by digit
  • letter 'c' followed by digit dash digit
  • digit may be followed by an other digit enclosed in square parentheses []

并按预期创建一个数组:

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

代码:

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

现在我想添加另一个 key,在 a 之后使用 digit 的值。 所以举个例子,给定上面的$str

$str = "a2c4-8|a6c2,c3-5,c6[2],c8[4]-10,c14-21[5]". 

a 的值是:26,预期的结果数组如下。 请注意, 6 会针对每个匹配的 c 重复。

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

【问题讨论】:

  • 由于每个数组键必须是唯一的,这是不可能的。
  • 好的。知道了。我改变了一点我的问题。请查看编辑后的帖子和预期的结果数组。
  • 如果从未定义过“a”或者如果“a”出现在第一个“c”之后会怎样?这些情况可能吗?
  • a 总是被定义并且它总是被| (explode("|",$str);) 分解的字符串的第一个字母

标签: php arrays regex


【解决方案1】:

你可以这样做:

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

但是,如果您已经确切知道字符串格式是怎样的,并且不需要验证它,那么可能有更聪明(更快)的方法来获得相同的结果。

例如,使用explode 和带有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);

【讨论】:

  • 完美。我很欣赏sscanf 的替代方案,这是我从未想过的......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-11-21
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
  • 2019-06-23
  • 2014-02-06
  • 2013-11-25
相关资源
最近更新 更多