javascript之計算算數關係表達式
背景
解決類似於3*15 == 5*9
的問題,或者更加複雜的3*15 == 5*9 >30
等表達式。
已有的解決表達式模塊
· jexl模塊
· eval函數
但是這些方法只能解決必須保證關係運算符一邊必須是具體的常數,不能是表達式。如:
3*15 == 45
。
解決方法
思路:先計算關係符號兩側的表達式再進行關係比較。
const _ = require('lodash');
const jexl = require('jexl');
// 分割出運算符和表達式
async _recursionDiv(expression, operations, operaList, list) {
const hasIndex = _.findIndex(operations, oper => {
return expression.indexOf(oper) >= 0;
});
if (hasIndex >= 0) {
operaList.push(operations[hasIndex]);
const splitList = expression.split(operations[hasIndex]);
const left = splitList[0];
const right = splitList[1];
await this._recursionDiv(left, operations, operaList, list);
await this._recursionDiv(right, operations, operaList, list);
} else {
const result = await jexl.eval(expression);
list.push(result);
}
}
// 算式先計算後比較(將算數表達式通過關係符號分割出來,生成一個存放關係符號的的數組和一個存放最小無關係表達式的算數表達式)
async _operationContentFormula(contentFormula) {
const operations = ['==', '>', '<', '>=', '<=', '!=', '!==', '==='];
// 最小無關係表達式的算數表達式
let list = [];
// 存放關係符號的的數組
let operaList = [];
const hasIndex = _.findIndex(operations, oper => {
return contentFormula.indexOf(oper) >= 0;
});
if (hasIndex >= 0) {
operaList.push(operations[hasIndex]);
const splitList = contentFormula.split(operations[hasIndex]);
// 關係運算符的左右兩側
const left = splitList[0];
const right = splitList[1];
await this._recursionDiv(left, operations, operaList, list);
await this._recursionDiv(right, operations, operaList, list);
}
// 根據兩個數組重新組裝成jexl模塊認可的表達式
let newExpression = '';
for (let i = 0; i < list.length; i++) {
if (i !== list.length - 1) {
newExpression += `${list[i]}${operaList[i]}`;
} else {
newExpression += `${list[i]}`;
}
}
const result = await jexl.eval(newExpression);
return result;
}
測試
const result = await this._operationContentFormula('3*15 == 5*9');
console.log(result); // true