最早想到的方式就是一个很简单的加减乘除,其实没那么简单。分析表达式的运算符与数字这些都必须先想好每一步。 最开始我的解决方法是用系统函数eval,但是有些时候eval函数会被禁止掉.就丢掉这个解决方案,谷歌了一下发现前辈早有很好的解决方案,就是用后缀表
最早想到的方式就是一个很简单的加减乘除,其实没那么简单。分析表达式的运算符与数字这些都必须先想好每一步。
最开始我的解决方法是用系统函数eval,但是有些时候eval函数会被禁止掉.就丢掉这个解决方案,谷歌了一下发现前辈早有很好的解决方案,就是用后缀表达式(逆波兰式)来运算,关于逆波兰式的算法,可以自己找一些资料。我直接贴出运算代码:
header("Content-type:text/html;charset=utf-8");
function deleteHtml($str)
{
$str = trim($str);
$str = strip_tags($str, "");
$str = ereg_replace(" ", "", $str);
$str = ereg_replace("
", "", $str);
$str = ereg_replace("
", "", $str);
$str = ereg_replace("
", "", $str);
$str = ereg_replace(" ", "", $str);
return trim($str);
}
/*
* 将中缀表达式转换成后缀表达式
* 也就是逆波兰式
*/
class math_rpn
{
private $expression = array(); //需要转换的中缀表达式
private $rpnexp = array(); //处理后的逆波兰式
private $stack = array('#'); //储存临时运算符栈
private $priority = array('#'=>0, '('=>10, '+' => 20, '-'=>20, '*'=>30, '/'=>30); //运算符优先级
private $operator = array('(', '+', '-', '*', '/', ')'); //四则运算符
public function __construct($expression)
{
$this->_init($expression);
}
private function get_token_array($string)
{
/* 构造记号流*/
$token = array();
$str_len = 0;
while (true)
{
if (1 === preg_match('/^([%,\^\+\-\*\/\(\)]).*$/',$string,$sub))
{
array_push($token,$sub[1]);
$string = substr($string,strlen($sub[1]));
$str_len += strlen($sub[1]);
continue;
}
elseif (1 === preg_match('/^(([0-9]+[\.]?[0-9]*)|([0-9]*[\.]?[0-9]+)).*$/',$string,$sub))
{
array_push($token,floatval($sub[1]));
$string = substr($string,strlen($sub[1]));
$str_len += strlen($sub[1]);
continue;
}
elseif (1 === preg_match('/^([a-zA-Z_][0-9a-zA-Z_]*\().*$/',$string,$sub))
{
array_push($token,$sub[1]);
$string = substr($string,strlen($sub[1]));
$str_len += strlen($sub[1]);
continue;
}
elseif (1 === preg_match('/^(\s+).*$/',$string,$sub))
{
$string = substr($string,strlen($sub[1]));
$str_len += strlen($sub[1]);
continue;
}
else
{
break;
}
}
if ($string != '')
{
return $str_len;
}
return $token;
}
private function _init($expression)
{
$exp = array();
$expression = deleteHtml($expression);
$exp = $this->get_token_array($expression);
if(!is_array($exp))
{
$str = substr($expression, $exp,1);
echo $expression,'表达式错误在',$str;
exit;
}
$this->expression = $exp;
}
public function exp2rpn()
{
$count = count($this->expression);
for($i = 0; $i<$count; $i++)
{
$char = $this->expression[$i]; //获取表达式中的每一个字符串
if ($char == '(') //如果字符为(,则直接存入$stack的栈顶
{
$this->stack[] = $char;
continue;
}
else if (!in_array($char, $this->operator)) //如果字符不为运算符,则压入$rpnexp中
{
$this->rpnexp[] = $char;
continue;
}
else if ($char == ')') //在$stack中查找最近"("之间的运算符,逐个出栈.送入栈$rpnexp中
{
for ($j =count($this->stack); $j >= 0; $j++)
{
$tmp = array_pop($this->stack);
if ($tmp == '(') //跳出循环
break;
else
$this->rpnexp[] = $tmp;
}
continue;
}
else if ($this->priority[$char] <= $this->priority[end($this->stack)])
{
$this->rpnexp[] = array_pop($this->stack);
$this->stack[] = $char;
continue;
}
else
{
$this->stack[] = $char;
continue;
}
}
//将存在临时的运算符栈剩余的内容存入rpnexp栈中
for($i=count($this->stack); $i>=0; $i++)
{
if(end($this->stack) == '#')
break;
else
$this->rpnexp[] = array_pop($this->stack);
}
return $this->rpnexp;
}
public function getResult($rpnexp)
{
$result = array();
$rpnexp = array_reverse($rpnexp); //将值倒叙
$count = count($rpnexp);
//如果有运算符就计算,否则将数据压入$result结果栈中
while($count>0)
{
$v = array_pop($rpnexp);
if(in_array($v, $this->operator))
{
$a = array_pop($result);
$b = array_pop($result);
switch($v)
{
case '+':
array_push($result, ($a+$b));
break;
case '-':
array_push($result, ($b-$a));
break;
case '*':
array_push($result, ($a*$b));
break;
case '/':
array_push($result, ($b/$a));
break;
default:
break;
}
}
else
array_push($result, $v);
$count--;
}
return array_pop($result);
}
}
$exp = "(30+3.1)*5/2-2";
$mathrpn = new math_rpn($exp);
$rpnExp = $mathrpn->exp2rpn();
echo $mathrpn->getResult($rpnExp);//80.75
?>原文地址:PHP 计算器, 感谢原作者分享。
PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号