123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- <?php
- namespace app\common\util;
- class ArithmeticCount
- {
- //运算符栈,在栈里插入最小优先级的运算符,避免进入不到去运算符比较的循环里
- protected $opArr = ['#'];
- //运算数栈;
- protected $oprandArr = [];
- //运算符优先级
- protected $opLevelArr = [
- ')' => 2,
- '(' => 3,
- '+' => 4,
- '-' => 4,
- '*' => 5,
- '/' => 5,
- '#' => 1
- ];
- protected $bolanExprArr = [];
- protected $exprLen=0;
- protected $inop = false;
- protected $opNums = "";
- protected $expr="";
- protected $bai=false;
- /**
- * Notes: 百分号转数字 查找替换
- * author 何腾骥
- * Date: 2018/9/27
- * Time: 11:51
- * @param $expr
- * @return array|string|string[]
- */
- protected function doReplace($expr)
- {
- $expr = str_replace(' ','' ,$expr);
- $expr = str_replace('(','(' ,$expr);
- $expr = str_replace(')',')' ,$expr);
- $expr = str_replace(' ','' ,$expr);
- preg_match_all("/\d+(\.\d+)?%/",$expr,$arr);
- if(isset($arr[0]) && !empty($arr[0])){
- foreach ($arr[0] as $val){
- $expr = str_replace($val,(float) $val /100 ,$expr);
- }
- return $expr;
- }
- if(preg_match("/100-\(/",$expr,$arr)){
- $expr = str_replace('100-','' ,$expr);
- $this->bai = true;
- }
- return $expr;
- }
- /**
- * Notes: 处理 计算
- * author 何腾骥
- * Date: 2018/9/27
- * Time: 11:53
- */
- public function makeCount($expr)
- {
- error_reporting(0);
- // 处理百分号
- $this->expr = $this->doReplace($expr);
- // 计算长度
- $this->exprLen = strlen($expr);
- //解析表达式
- for($i = 0;$i <= $this->exprLen;$i++){
- $char = $this->expr[$i];
- //获取当前字符的优先级
- $level = intval($this->opLevelArr[$char]);
- //如果大于0,表示是运算符,否则是运算数,直接输出
- if($level > 0){
- $this->inop = true;
- //如果碰到左大括号,直接入栈
- if($level == 3){
- array_push($this->opArr,$char);continue;
- }
- //与栈顶运算符比较,如果当前运算符优先级小于栈顶运算符,则栈顶运算符弹出,一直到当前运算符优先级不小于栈顶
- while($op = array_pop($this->opArr)){
- if($op){
- $currentLevel = intval($this->opLevelArr[$op]);
- if($currentLevel == 3 && $level == 2) {
- break;
- }elseif($currentLevel >= $level && $currentLevel != 3){
- array_push($this->bolanExprArr,$op);
- }else{
- array_push($this->opArr,$op);
- array_push($this->opArr,$char);
- break;
- }
- }
- }
- }else{
- //多位数拼接成一位数
- $this->opNums .= $char;
- if($this->opLevelArr[$this->expr[$i+1]] > 0){
- array_push($this->bolanExprArr, $this->opNums);
- $this->opNums = "";
- }
- }
- }
- array_push($this->bolanExprArr, $this->opNums);
- //输出剩余运算符
- while($leftOp = array_pop($this->opArr)){
- if($leftOp != '#'){
- array_push($this->bolanExprArr,$leftOp);
- }
- }
- //计算逆波兰表达式。
- foreach($this->bolanExprArr as $v){
- if(!isset($this->opLevelArr[$v])){
- array_push($this->oprandArr,$v);
- }else{
- $op1 = array_pop($this->oprandArr);
- $op2 = array_pop($this->oprandArr);
- eval("\$result = $op2 $v $op1;");
- array_push($this->oprandArr,$result);
- }
- }
- if($this->bai){
- return 100 - $result;
- }
- return $result;
- }
- }
|