【问题标题】:Parsing nested curly brace with php regex使用 php 正则表达式解析嵌套的大括号
【发布时间】:2017-05-07 06:59:21
【问题描述】:

我想将带有嵌套花括号的原始字符串解析为多维数组。下面我添加了有效的示例代码。但主要问题是我的正则表达式只捕获第一个匹配的组并忽略另一个出现。

非常感谢任何帮助。

代码:

$regex = '/(?ims)(group [a-z0-9\s\,\.\:#_\-@]+)\{([^\}]*)\}/';
preg_match_all( $regex, file_get_contents('data.txt', FILE_USE_INCLUDE_PATH), $arr); 
    $result = array();
    foreach ($arr[0] as $i => $x)
    {
        $selector = trim($arr[1][$i]);
        $rules = explode(';', trim($arr[2][$i]));
        $result[$selector] = array();
        foreach ($rules as $strRule)
        {
            if (!empty($strRule))
            {
                $rule = explode(" = ", $strRule);
                $result[$selector][][trim($rule[0])] = trim($rule[1]);
            }
        }
    }

原始字符串(data.txt):

group A { T1 { X = 44; }
          T2 { Y = 33; } }

group B { T1 { X = 555; } }

代码输出:

Array (
    [group A] => Array ( 
        [0] => Array ( 
            [T1 { X] => 44 
        ) 
    )
    [group B] => Array ( 
        [0] => Array ( 
            [T1 { X] => 555 
        ) 
    )
)

但输出除外:

Array(
    [group A] => Array(
        [T1] => Array(
            [X] => 44
        ) 
        [T2] => Array (
            [Y] => 33
        )
    )
    [group B] => Array(
        [T1] => Array(
            [X] => 555
        )
    )
)

【问题讨论】:

  • 你能分享这个原始字符串group A { T1 { X = 44; } T2 { Y = 33; } }的预期输出吗?
  • Array ([group A] => Array ( [0] => Array ( [T1 { X] => 44 )[1] => Array ( [T2 { Y] => 33) )[组 B] => 数组 ( [0] => 数组 ([T1 { X] => 555 ) ) )
  • 为什么输出中有大括号?你确定这真的是输出吗?
  • 因为细化正则表达式模式也不会解析字符串中的嵌套大括号。这就是问题所在。

标签: php arrays regex multidimensional-array


【解决方案1】:

可能存在更好的解决方案,但它确实有效。

确保您的输入不能有更深层次的价值,否则您必须改进/重写整个规则!

$input = <<<REG
group A { T1 { X = 44; }
          T2 { Y = 33; } }

group B { T1 { X = 555; } }
REG;

$out   = [];
$cbuff = null;
$rule  = "/^(?<group>[^\{\}]*)?\{|((?<set>[\w\s]+)\{(?<var>[\w\s]+)=(?<val>[\d\s]+)[;\s]+\})/im";
preg_replace_callback($rule, function($m)
use(&$out, &$cbuff) // import locally our working requirements
{
    $m = array_filter($m, "is_string", ARRAY_FILTER_USE_KEY); // cleaning
    $m = array_map("trim", array_filter($m)); // cleaning and trim

    if(key($m)=="group") // get & create the current root group
        $out[($cbuff = reset($m))] = [];

    if(isset($m["var"])) // assuming 'var' exists, you'll get 'set/var' too
    {
        if(is_null($cbuff)) return; // prevent no group found
        $out[$cbuff][$m["set"]] = [$m["var"] => $m["val"]];
    }
}, $input);

var_dump($out);

将输出:

array(2) {
  ["group A"]=>
  array(2) {
    ["T1"]=>
    array(1) {
      ["X"]=>
      string(2) "44"
    }
    ["T2"]=>
    array(1) {
      ["Y"]=>
      string(2) "33"
    }
  }
  ["group B"]=>
  array(1) {
    ["T1"]=>
    array(1) {
      ["X"]=>
      string(3) "555"
    }
  }
}

提示

我认为你对 PHP 没问题, 但我对正则表达式做了一点解释:

首先我为每个部分“set/var/val”模式使用了“命名组”:?&lt;name&gt;

在匹配输出下授予自己的组密钥

(?&lt;set&gt;...)|(?&lt;var&gt;...) 给出 --> ["set" =&gt; ...], ["var" =&gt; "..."]

最后,将子属性分离到根组, 我只是匹配任何不包含括号的部分

长凳

你可以在regex101找回我的板凳

3 matches, 60 steps (~0ms)
5 matches, 107 steps (~0ms)

是的,可以优化!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 2010-12-26
    • 2014-11-27
    • 2014-10-09
    相关资源
    最近更新 更多