如何在不使用eval()的情况下计算数学表达式的结果,同时考虑算术运算符的优先级


这个问题有一个简单的答案。如果使用eval()方法,php将完美地求解数学表达式并返回正确的结果。
$expression = "27+38+81+48*33*53+91*53+82*14+96";
$result = eval('return '.$expression.';');
echo $result;

在不使用eval()的情况下如何解决此问题?

下面的函数将解析简单的数学表达式并计算结果。

<?php

echo "90165: ".calculate("27+38+81+48*33*53+91*53+82*14+96")."n";
// calculates the result of an expression in infix notation
function calculate($exp) {
return calculate_rpn(mathexp_to_rpn($exp));
}
// calculates the result of an expression in reverse polish notation
function calculate_rpn($rpnexp) {
$stack = array();
foreach($rpnexp as $item) {
if (is_operator($item)) {
if ($item == '+') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i + $j);
}
if ($item == '-') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i - $j);
}
if ($item == '*') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i * $j);
}
if ($item == '/') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i / $j);
}
if ($item == '%') {
$j = array_pop($stack);
$i = array_pop($stack);
array_push($stack, $i % $j);
}
} else {
array_push($stack, $item);
}
}
return $stack[0];
}
// converts infix notation to reverse polish notation
function mathexp_to_rpn($mathexp) {
$precedence = array(
'(' => 0,
'-' => 3,
'+' => 3,
'*' => 6,
'/' => 6,
'%' => 6
);

$i = 0;
$final_stack = array();
$operator_stack = array();
while ($i < strlen($mathexp)) {
$char = $mathexp{$i};
if (is_number($char)) {
$num = readnumber($mathexp, $i);
array_push($final_stack, $num);
$i += strlen($num); continue;
}
if (is_operator($char)) {
$top = end($operator_stack);
if ($top && $precedence[$char] <= $precedence[$top]) {
$oper = array_pop($operator_stack);
array_push($final_stack, $oper);
}
array_push($operator_stack, $char);
$i++; continue;
}
if ($char == '(') {
array_push($operator_stack, $char);
$i++; continue;
}
if ($char == ')') {
// transfer operators to final stack
do {
$operator = array_pop($operator_stack);
if ($operator == '(') break;
array_push($final_stack, $operator);
} while ($operator);
$i++; continue;
}
$i++;
}
while ($oper = array_pop($operator_stack)) {
array_push($final_stack, $oper);
}
return $final_stack;
}
function readnumber($string, $i) {
$number = '';
while (is_number($string{$i})) {
$number .= $string{$i};
$i++;
}
return $number;
}
function is_operator($char) {
static $operators = array('+', '-', '/', '*', '%');
return in_array($char, $operators);
}
function is_number($char) {
return (($char == '.') || ($char >= '0' && $char <= '9'));
}
?>

函数mathexp_to_rpn()将中缀表示法(如"3 + 2"(中的数学表达式转换为反向抛光表示法(RPN(中的表达式:"3 2 +"。这更容易计算,这是通过函数calculate_rpn()完成的。运算符优先级和括号都会考虑在内。没有检查输入是否是有效的表达式。除法不是很精确。

考虑一下已经为您完成此操作的EvalMath类:https://github.com/dbojdo/eval-math

最新更新