【问题标题】:How to parse recursive parentheses correctly?如何正确解析递归括号?
【发布时间】:2019-04-14 03:54:31
【问题描述】:

我需要解析一个包含一些以递归方式处理的括号的字符串,但我在确定括号的优先级时遇到了麻烦。 例如,我有字符串

$truth = "((A^¬B)->C)";

我需要返回括号之间的内容。我已经使用以下正则表达式完成了它:

preg_match_all("~\((.*?)\)~", $truth, $str);

但问题是它返回第一个“(”和第一个“)”之间的内容,即

(A^¬B

而不是这个,我需要它“知道”括号正确关闭的位置,以便返回

(A^¬B)->C

如何根据优先顺序返回此内容?谢谢!

【问题讨论】:

  • 您可以只创建一个排除组并将括号之外的任何内容与[^\(\)]* 而不是.* 匹配,但您可能仍会遇到问题,具体取决于您尝试的表达式的复杂性解析,特别是如果它格式错误。正则表达式很方便,但并不适用于所有解析问题。
  • 正则表达式不足以解析语言。尝试解析器生成器。 stackoverflow.com/questions/3720362/…

标签: php regex


【解决方案1】:

对于您的示例字符串,类似这样的内容将递归地为您提供括号的内容。它通过在正则表达式的每一端使用^[^(]*[^)]*$ 强制匹配的括号成为最外层的一对。

$truth = "((A^¬B)->C)";
while (strpos($truth, '(') !== false) {
    preg_match("~^[^(]*\((.*?)\)[^)]*$~", $truth, $str);
    $truth = $str[1];
    echo "$truth\n";
}

输出

(A^¬B)->C 
A^¬B

但请注意,这将无法正确解析诸如(A+B)-(C+D) 之类的字符串。如果这可能是您的情况,this answer 可能会有所帮助。

Demo on 3v4l.org

【讨论】:

    【解决方案2】:

    您现在遇到的主要问题是? 非贪婪位。如果您将其更改为 .+ greedy 它将匹配您想要的。

    $truth = "((A^¬B)->C)";
    preg_match('/\(.+\)/', $truth, $match);
    

    Try it

    输出

    (A^¬B)->C
    

    如果要匹配内部对,可以使用递归子模式:

    $truth = "((A^¬B)->C)";
    preg_match('/\(([^()]+|(?0))\)/', $truth, $match);
    

    Try It online

    输出

    A^¬B
    

    如果您需要更进一步,那么您可以制作一个词法分析器/解析器。我这里有一些例子:

    https://github.com/ArtisticPhoenix/MISC/tree/master/Lexers

    【讨论】:

    • 谢谢!它解决了我的问题。也感谢其他人,它将很有用。 =D
    • 当然,我刚刚将输出转换器添加到我的网站,artisticphoenix.com/2018/11/11/output-converter 它使用相同的解析思想,但可以将 var_export 和 print_r 转换为可用数组。我必须在这里做很多事情......大声笑
    • @ArtisticPhoenix 我只是在想我将不得不自己编写相同的工具!感谢分享...
    • 当然,我的网站仍在进行中。哈哈。不幸的是,我没有太多时间来研究它
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 2019-01-06
    相关资源
    最近更新 更多