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

问题描述

假设我有这个字符串:

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

我想将其拆分为运算符和非运算符数组,但不得拆分 ()' 之间的任何内容。

我希望输出是:

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

我正在使用此代码:

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

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

[1,"(3","(23",53,"(132 / 5)","5)","1)",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 ?~",PREG_SPLIT_NO_EMPTY
)

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

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...