【问题标题】:Parsing a string with recursive parentheses使用递归括号解析字符串
【发布时间】:2016-02-16 18:43:39
【问题描述】:

我正在尝试在 PHP 中解析具有以下结构的字符串:

a,b,c(d,e,f(g),h,i(j,k)),l,m,n(o),p

例如,“真实”字符串将是:

id,topic,member(name,email,group(id,name)),message(id,title,body)

我的最终结果应该是一个数组:

[
   id => null,
   topic => null
   member => [
      name => null,
      email => null,
      group => [
         id => null,
         name => null
      ]
   ],
   message => [
      id => null,
      title => null,
      body => null
  ]
]

我尝试了递归正则表达式,但完全迷路了。 我在迭代字符串字符方面取得了一些成功,但这似乎有点“过于复杂”,我确信这是正则表达式可以处理的东西,我只是不知道如何处理。

目的是解析一个REST API的字段查询参数,让客户端从复杂的对象集合中选择他想要的字段,我不想限制字段选择的“深度”。

【问题讨论】:

  • 您不需要正则表达式。您可以编写一个简单的解析器来完成这项工作。
  • 好的,那我需要什么?手动迭代字符串?
  • 有一个几乎相同的问题,如果回答者没有尽快发布解决方案,我会尝试找到该代码。
  • 抱歉,很难找到答案。我可以推荐看看this answer,它展示了如何在 PHP 中实现示例解析器。
  • 谢谢。手动解析字符串并不“漂亮”,但我已经设法手动解决它,对于任何实际深度(将其测试到 20 级深度,这对于我需要的目的来说是过度杀戮)。我稍后会上传代码,因为它目前都很乱。仍然希望有人提出一个“干净”的解决方案。

标签: php regex recursion


【解决方案1】:

正如 Wiktor 指出的,这可以在词法分析器的帮助下实现。以下答案使用了来自 Nikita Popopv 的一个类,可以在 here 找到。

它的作用

它会浏览字符串并搜索$tokenMap 中定义的匹配项。这些被定义为T_FIELDT_SEPARATORT_OPENT_CLOSE。找到的值被放入一个名为 $structure 的数组中。
之后我们需要遍历这个数组并从中构建结构。由于可以有多个嵌套,因此我选择了递归方法 (generate())。

演示

一个demo can be found on ideone.com

代码

带解释的实际代码:

// this is our $tokenMap
$tokenMap = array(
    '[^,()]+'       => T_FIELD,     # not comma or parentheses
    ','             => T_SEPARATOR, # a comma
    '\('            => T_OPEN,      # an opening parenthesis
    '\)'            => T_CLOSE      # a closing parenthesis
);

// this is your string
$string = "id,topic,member(name,email,group(id,name)),message(id,title,body)";

// a recursive function to actually build the structure
function generate($arr=array(), $idx=0) {
    $output = array();
    $current = null;
    for($i=$idx;$i<count($arr);$i++) {
        list($element, $type) = $arr[$i];
        if ($type == T_OPEN)
            $output[$current] = generate($arr, $i+1);
        elseif ($type == T_CLOSE)
            return $output;
        elseif ($type == T_FIELD) {
            $output[$element] = null;
            $current = $element;
        }
    }
    return $output;
}

$lex = new Lexer($tokenMap);
$structure = $lex->lex($string);

print_r(generate($structure));

【讨论】:

  • 嗯,这是我会考虑使用的东西,当然。不过,我相信还有更简单的方法。
  • 效果很好!我做了类似的事情,但没有递归,所以这比我的解决方案更干净。谢谢!
  • 我在 PHP 7.0 中得到了很多“使用未定义的常量 T_FIELD”(也包括 T_SEPARATOR、T_OPEN、T_CLOSE)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-07
  • 2021-07-29
  • 2019-04-14
  • 2021-11-18
相关资源
最近更新 更多