PHP四则运算类(支持加、减、乘、除、小中括号)

<?php

/**
 * 四则运算(支持加、减、乘、除、小中括号)
 * Class calculator
 */
class calculator {
    //保留几位小数点
    public $point = 2;

    public function __construct($point=2)
    {
        $this->point = $point;
    }

    /**
     * 四则运算(支持加、减、乘、除、小中括号)
     * @param $str  表达式
     * @throws Exception
     * @author fengzi
     * @date   2022-07-12 14:42
     */
    function expression($str)
    {
        try {
            $str         = str_replace(' ', '', $str);
            $arr         = preg_split('/([\+\-\*\/\(\)\[\]])/', $str, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
            $numStack    = [];// 存放数字
            $operStack   = [];// 存放运算符
            $operStack[] = NULL;
            for ($i = 0; $i < count($arr); $i++) {

                //把数字放入$numStack
                if (ord($arr[$i]) >= 48 && ord($arr[$i]) <= 57) {
                    array_push($numStack, $arr[$i]);
                    continue;
                }

                switch ($arr[$i]) {
                    case '+':
                    case '-':
                        $arrLen = count($operStack);
                        while ($operStack[$arrLen - 1] === '*' || $operStack[$arrLen - 1] === '/' || $operStack[$arrLen - 1] === '-') {
                            $this->compute($numStack, $operStack);
                            $arrLen--;
                        }
                        array_push($operStack, $arr[$i]);
                        break;
                    case '*':
                        $arrLen = count($operStack);
                        while ($operStack[$arrLen - 1] === '/') {
                            $this->compute($numStack, $operStack);
                            $arrLen--;
                        }
                        array_push($operStack, $arr[$i]);
                        break;
                    case '/':
                    case '(':
                    case '[':
                        array_push($operStack, $arr[$i]);
                        break;
                    case ']':
                        $arrLen = count($operStack);
                        while ($operStack[$arrLen - 1] !== '[') {
                            $this->compute($numStack, $operStack);
                            $arrLen--;
                        }
                        array_pop($operStack);
                        break;
                    case ')':
                        $arrLen = count($operStack);
                        while ($operStack[$arrLen - 1] !== '(') {
                            $this->compute($numStack, $operStack);
                            $arrLen--;
                        }
                        array_pop($operStack);
                        break;
                    default:
                        throw new \Exception("不支持的运算符", 1);
                        break;
                }
            }

            $arrLen = count($operStack);
            while ($operStack[$arrLen - 1] !== NULL) {
                $this->compute($numStack, $operStack);
                $arrLen--;
            }

            return array_pop($numStack);
        } catch (Exception $e) {
            return $e->getMessage();
        }
    }


    /**
     * 数字栈长度减一,运算符栈长度减一
     * @param $numStack     存放数字
     * @param $operStack    存放运算符
     * @throws Exception
     * @author fengzi
     * @date   2022-07-12 14:44
     */
    function compute(&$numStack, &$operStack){
        $num = array_pop($numStack);

        //运算结果四舍五入
        $caseKey = array_pop($operStack);
        switch ($caseKey) {
            case '*':
                array_push($numStack, number_format(array_pop($numStack) * $num, $this->point, '.', ''));
                break;
            case '/':
                array_push($numStack, number_format(array_pop($numStack) / $num, $this->point, '.', ''));
                break;
            case '+':
                array_push($numStack, number_format(array_pop($numStack) + $num, $this->point, '.', ''));
                break;
            case '-':
                array_push($numStack, number_format(array_pop($numStack) - $num, $this->point, '.', ''));
                break;
            case '(':
            case '[':
                throw new \Exception("不匹配的{$caseKey}");
                break;
            default:
                throw new \Exception("未知符号");
                break;
        }
    }
}

  

posted @ 2022-07-12 15:26  疯子丶pony  阅读(274)  评论(0编辑  收藏  举报