将数学表达式拆分为数组而不拆分括号和单引号之间的子表达式
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)|([+\-*/^])
$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 上完成了 技术,就像这样。另一个考虑因素是:您想如何处理带符号的数字?数字实体应该保留符号符号还是应该像运算符一样分开?
假设我有这个字符串:
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)|([+\-*/^])
$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 上完成了