我正在尝试用括号包装表达式。表达式从一些数字数学开始,以一个单位结束,例如:
4+(5+6)*3 meter
(23+4)*3*(76+5) second
我想要的结果是:
(4+(5+6)*3) meter
((23+4)*3*(76+5)) second
问题是该函数是递归调用的,只有在preg_replace
后的字符串中有无变化时才会停止,所以下面的尝试:
preg_replace('/(.+)(?=\s+[a-z]+$)/', '($1)', '4+(5+6)*3 meter')
永远不会停止,结果将是:
(4+(5+6)*3) meter
((4+(5+6)*3)) meter
(((4+(5+6)*3))) meter
etc..
我想知道是否有办法在数学部分尚未用括号括起来进行替换。表达式的第二个例子将使解决方案更难一点。
答案 0 :(得分:1)
我下班后试过这个,我觉得这样可行。我的想法是通过删除壁橱匹配括号重复减少表达式,直到不再剩余。如果最终表达式非空,那么我们需要用括号包装原始表达式,否则我们不会。
例如,如果表达式为((1+2)*(2+1))+1
,则缩减如下:
这里的最终值非空,所以我们扭曲表达式:(((1+2)*(2+1))+1)
。
以下是代码:
$input = $output = '(23+4)*3*(76+5) meter';
// Split into arithmetic expression and the unit string bit
if (preg_match('/^(.+?)\s*([a-z]+)$/', $input, $match)) {
$exp = $match[1];
$unit = $match[2];
// This is the main logic
// Reduce the expression by repetitively removing closet matching parenthesis
$reduced_exp = $exp;
do {
// The fifth parameter $count returns the number replacements done
$reduced_exp = preg_replace('/\([^()]+\)/', '', $reduced_exp, -1, $count);
} while ($count); // Exit the loop if there are zero replacements
// If reduced expression is non-empty then we need to wrap it with the parenthesis
if (!empty($reduced_exp)) {
$output = '('.$exp.') '.$unit;
}
}
print_r($output); // Outputs ((23+4)*3*(76+5))
答案 1 :(得分:0)
您需要确保您的第一个捕获组添加了不在括号内的约束:
preg_replace('/^([^(].+?[^)])(?=\s+[a-z]+$)/', '($1)', '4+(5+6)*3 meter')
修改强>
如@Talvir所述,这在以下情况下不起作用:
(1+2)*(3+4)
因为这意味着我们需要使用堆栈计算机跟踪打开和关闭括号(以及正则表达式不具备的功能),我认为没有正则表达式的解决方案。