|
@@ -10,6 +10,7 @@
|
|
|
|
|
|
const fs = require('fs');
|
|
|
const streamToArray = require('stream-to-array');
|
|
|
+const mathjs = require('mathjs');
|
|
|
|
|
|
module.exports = {
|
|
|
/**
|
|
@@ -208,4 +209,148 @@ module.exports = {
|
|
|
}
|
|
|
return json;
|
|
|
},
|
|
|
+
|
|
|
+ isOperator(value) {
|
|
|
+ const operatorString = "+-*/()";
|
|
|
+ return operatorString.indexOf(value) > -1
|
|
|
+ },
|
|
|
+ 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;
|
|
|
+ },
|
|
|
+ evalRpn(rpnQueue) {
|
|
|
+ const getResult = function (num1, num2, opera) {
|
|
|
+ switch (opera) {
|
|
|
+ case '+':
|
|
|
+ return num1 + num2;
|
|
|
+ case '-':
|
|
|
+ return num1 - num2;
|
|
|
+ case '*':
|
|
|
+ return num1 * num2;
|
|
|
+ case '/':
|
|
|
+ return num1 / num2;
|
|
|
+ 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 ? NaN : result;
|
|
|
+ }
|
|
|
+ } catch (err) {
|
|
|
+ return NaN;
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ calcExprStr(expr) {
|
|
|
+ try {
|
|
|
+ const result = mathjs.eval(expr);
|
|
|
+ return result === Infinity ? NaN : result;
|
|
|
+ } catch (err) {
|
|
|
+ return NaN;
|
|
|
+ }
|
|
|
+ }
|
|
|
};
|