将数学表达式拆分为数组而不拆分括号和单引号之间的子表达式

Split mathematic expression into array without splitting subexpressions between parentheses and single quotes

假设我有这个字符串:

1 + 2 * (3 + (23 + 53 - (132 / 5) + 5) - 1) + 2 / 'test + string' - 52

我想把它拆分成一个运算符和非运算符的数组,但是 ()' 之间的任何东西都不能拆分。

我希望输出为:

[1, "+", 2, "*", "(3 + (23 + 53 - (132 / 5) + 5) - 1)", "+", 2, "/", "'test + string'", "-", 52]

我正在使用此代码:

preg_split("~['\(][^'()]*['\)](*SKIP)(*F)|([+\-*/^])+~", $str, -1, PREG_SPLIT_DELIM_CAPTURE);

该技术对运算符和 ' 做了我想要的,但对 () 没有。但是它只保留 (132 / 5) (最深的嵌套括号表达式)并拆分所有其他的,给我这个输出:

[1, "+", 2, "*", "(3", "+", "(23", "+", 53, "-", "(132 / 5)", "+", "5)", "-", "1)", "+", 2, "/", "'test + string'", "-", 52]

如何确保最外面的括号表达式及其所有内容保持在一起?

您可以使用模式递归匹配平衡括号的第一个子模式,然后使用 SKIP FAIL。交替后,您仍然可以使用捕获组,这将是组 2,并且由于 PREG_SPLIT_DELIM_CAPTURE 标志,这些值将被保留。

要删除空条目,您可以添加 PREG_SPLIT_NO_EMPTY 标志。

(?:(\((?:[^()]++|(?1))*\))|'[^']*')(*SKIP)(*F)|([+\-*/^])

Regex demo

$str = "1 + 2 * (3 + (23 + 53 - (132 / 5) + 5) - 1) + 2 / 'test + string' - 52";
$result = preg_split("~(?:(\((?:[^()]++|(?1))*\))|'[^']*')(*SKIP)(*F)|([+\-*/^])~", $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

print_r($result);

输出

Array
(
    [0] => 1 
    [1] => +
    [2] =>  2 
    [3] => *
    [4] =>  (3 + (23 + 53 - (132 / 5) + 5) - 1) 
    [5] => +
    [6] =>  2 
    [7] => /
    [8] =>  'test + string' 
    [9] => -
    [10] =>  52
)

我确实喜欢@thefourthbird 的递归子模式,但我更愿意标准化输出元素,以便删除所有空格。

我不会使用定界符捕获或跳过失败,但会重新启动全字符串 (\K) 以省略空格。

代码:(Demo)

preg_split(
    "~(?:(\((?:[^()]+|(?1))*\))|'[^']*'|[\d.]+|[*/^+-])\K ?~",
    $str,
    -1,
    PREG_SPLIT_NO_EMPTY
)

我已经在 SO 上完成了 技术,就像这样。另一个考虑因素是:您想如何处理带符号的数字?数字实体应该保留符号符号还是应该像运算符一样分开?