如何正确解析递归括号?

时间:2018-11-11 01:22:50

标签: php regex

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

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

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

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

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

  

(A ^¬B

相反,我需要它“知道”括号正确关闭的位置,以便返回

  

(A ^¬B)-> C

如何按照优先顺序退回此物品?谢谢!

2 个答案:

答案 0 :(得分:3)

对于您的示例字符串,类似的内容将递归给您括号的内容。通过在正则表达式的两端使用^[^(]*[^)]*$来强制匹配的括号成为最外面的一对。

$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

答案 1 :(得分:3)

您当前遇到的主要问题是?的非贪婪位。如果将其更改为仅.+贪婪,它将满足您的需求。

$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