|
@@ -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}
|
|
|
})();
|