| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 | <?phpnamespace 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;    }}
 |