|  | @@ -122,5 +122,156 @@ const ZhCalc = (function () {
 | 
	
		
			
				|  |  |          return value ? new Decimal(value).toDecimalPlaces(decimal).toNumber() : null;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    return {add, sub, mul, div, round, isNonZero: zhBaseCalc.isNonZero}
 | 
	
		
			
				|  |  | +    const ExprCalc = {
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * 判断value是否是四则运算符
 | 
	
		
			
				|  |  | +         * @param {String} value - 判断字符串
 | 
	
		
			
				|  |  | +         * @return {Boolean}
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        isOperator(value) {
 | 
	
		
			
				|  |  | +            const operatorString = "+-*/()";
 | 
	
		
			
				|  |  | +            return operatorString.indexOf(value) > -1;
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * Rpn解析栈
 | 
	
		
			
				|  |  | +         * @param exp
 | 
	
		
			
				|  |  | +         * @returns {Array}
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        parse2Rpn(exp) {
 | 
	
		
			
				|  |  | +            const getPriority = function (value){
 | 
	
		
			
				|  |  | +                switch(value){
 | 
	
		
			
				|  |  | +                    case '+':
 | 
	
		
			
				|  |  | +                    case '-':
 | 
	
		
			
				|  |  | +                        return 1;
 | 
	
		
			
				|  |  | +                    case '*':
 | 
	
		
			
				|  |  | +                    case '/':
 | 
	
		
			
				|  |  | +                        return 2;
 | 
	
		
			
				|  |  | +                    default:
 | 
	
		
			
				|  |  | +                        return 0;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +            const priority = function (o1, o2){
 | 
	
		
			
				|  |  | +                return getPriority(o1) <= getPriority(o2);
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            const inputStack = [];
 | 
	
		
			
				|  |  | +            const outputStack = [];
 | 
	
		
			
				|  |  | +            const outputQueue = [];
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            for (let i = 0, len = exp.length; i < len; i++) {
 | 
	
		
			
				|  |  | +                const cur = exp[i];
 | 
	
		
			
				|  |  | +                if (cur !== ' ' ) {
 | 
	
		
			
				|  |  | +                    inputStack.push(cur);
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            let num = '', isNumPre = false, isOperatorPre = false;
 | 
	
		
			
				|  |  | +            while(inputStack.length > 0){
 | 
	
		
			
				|  |  | +                const cur = inputStack.shift();
 | 
	
		
			
				|  |  | +                if (this.isOperator(cur) && !(cur === '-' && !isNumPre)) {
 | 
	
		
			
				|  |  | +                    if (isNumPre) {
 | 
	
		
			
				|  |  | +                        outputQueue.push(parseFloat(num));
 | 
	
		
			
				|  |  | +                        num = '';
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    if (cur === '(') {
 | 
	
		
			
				|  |  | +                        outputStack.push(cur);
 | 
	
		
			
				|  |  | +                    } else if (cur === ')') {
 | 
	
		
			
				|  |  | +                        let po = outputStack.pop();
 | 
	
		
			
				|  |  | +                        while (po !== '(' && outputStack.length > 0) {
 | 
	
		
			
				|  |  | +                            outputQueue.push(po);
 | 
	
		
			
				|  |  | +                            po = outputStack.pop();
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        if (po !== '(') {
 | 
	
		
			
				|  |  | +                            throw "error: unmatched ()";
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    } else {
 | 
	
		
			
				|  |  | +                        while(priority(cur, outputStack[outputStack.length - 1]) && outputStack.length > 0){
 | 
	
		
			
				|  |  | +                            outputQueue.push(outputStack.pop());
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        outputStack.push(cur);
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    isNumPre = false;
 | 
	
		
			
				|  |  | +                    isOperatorPre = true;
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    num = num + cur;
 | 
	
		
			
				|  |  | +                    isNumPre = true;
 | 
	
		
			
				|  |  | +                    isOperatorPre = false;
 | 
	
		
			
				|  |  | +                    if (inputStack.length === 0) {
 | 
	
		
			
				|  |  | +                        outputQueue.push(parseFloat(num));
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            if (outputStack.length > 0) {
 | 
	
		
			
				|  |  | +                if (outputStack[outputStack.length - 1] === ')' || outputStack[outputStack.length - 1] === '(') {
 | 
	
		
			
				|  |  | +                    throw "error: unmatched ()";
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +                while (outputStack.length > 0) {
 | 
	
		
			
				|  |  | +                    outputQueue.push(outputStack.pop());
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +            return outputQueue;
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * 计算Rpn解析栈
 | 
	
		
			
				|  |  | +         * @param rpnQueue
 | 
	
		
			
				|  |  | +         * @returns {*}
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        evalRpn(rpnQueue) {
 | 
	
		
			
				|  |  | +            const getResult = function (num1, num2, opera) {
 | 
	
		
			
				|  |  | +                switch (opera) {
 | 
	
		
			
				|  |  | +                    case '+':
 | 
	
		
			
				|  |  | +                        return add(num1, num1);
 | 
	
		
			
				|  |  | +                    case '-':
 | 
	
		
			
				|  |  | +                        return sub(num1, num2);
 | 
	
		
			
				|  |  | +                    case '*':
 | 
	
		
			
				|  |  | +                        return mul(num1, num2, 10);
 | 
	
		
			
				|  |  | +                    case '/':
 | 
	
		
			
				|  |  | +                        return div(num1, num2, 10);
 | 
	
		
			
				|  |  | +                    default:
 | 
	
		
			
				|  |  | +                        throw '参数错误';
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            };
 | 
	
		
			
				|  |  | +            const outputStack = [];
 | 
	
		
			
				|  |  | +            while(rpnQueue.length > 0){
 | 
	
		
			
				|  |  | +                const cur = rpnQueue.shift();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                if (!this.isOperator(cur)) {
 | 
	
		
			
				|  |  | +                    outputStack.push(cur);
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    if (outputStack.length < 2) {
 | 
	
		
			
				|  |  | +                        throw "unvalid stack length";
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                    const sec = outputStack.pop();
 | 
	
		
			
				|  |  | +                    const fir = outputStack.pop();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    outputStack.push(getResult(fir, sec, cur));
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if (outputStack.length !== 1) {
 | 
	
		
			
				|  |  | +                throw "unvalid expression";
 | 
	
		
			
				|  |  | +            } else {
 | 
	
		
			
				|  |  | +                return outputStack[0];
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +        /**
 | 
	
		
			
				|  |  | +         * 解析四则运算字符串并计算
 | 
	
		
			
				|  |  | +         * @param {String} expr
 | 
	
		
			
				|  |  | +         * @returns
 | 
	
		
			
				|  |  | +         */
 | 
	
		
			
				|  |  | +        calcExprStrRpn(expr) {
 | 
	
		
			
				|  |  | +            try {
 | 
	
		
			
				|  |  | +                if (!isNaN(Number(expr))) {
 | 
	
		
			
				|  |  | +                    return Number(expr);
 | 
	
		
			
				|  |  | +                } else {
 | 
	
		
			
				|  |  | +                    const rpnArr = this.parse2Rpn(expr);
 | 
	
		
			
				|  |  | +                    const result = this.evalRpn(rpnArr);
 | 
	
		
			
				|  |  | +                    return result === Infinity ? null : result;
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            } catch (err) {
 | 
	
		
			
				|  |  | +                return null;
 | 
	
		
			
				|  |  | +            }
 | 
	
		
			
				|  |  | +        },
 | 
	
		
			
				|  |  | +    };
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    return {add, sub, mul, div, round, isNonZero: zhBaseCalc.isNonZero, calcExpr: ExprCalc}
 | 
	
		
			
				|  |  |  })();
 |