js实现输入数学公式和参数,计算结果

mathjs库和math-expression-evaluator库也可以实现
输入数学公式和参数,计算结果

class CalFormula {
    constructor(formula, params) {
        this.formula = formula
        this.params = params
    }
    // 公式字符串转换成token数组(中缀表达式)
    formulaToToken() {
        // 匹配运算符和空格
        const REG = /[()+\-/\*\^ ]/g;
        const params = this.formula.split(REG).filter(Boolean)
        const tokens = []
        let tmpStr = this.formula.replace(/\s/g,'')
        while (tmpStr.length > 0) {
            if(tmpStr.startsWith(params[0])) {
                tmpStr = tmpStr.replace(params[0], '')
                tokens.push(params.shift())
            } else {
                tokens.push(tmpStr[0])
                tmpStr = tmpStr.substring(1)
            }
        }
        return tokens
    }
    // 中缀表达式转换成后缀表达式(逆波兰表达式)
    toPostfix() {
        const operatorRank = { 
            '(': 0, 
            ')': 0, 
            '+': 1, 
            '-': 1, 
            '*': 2, 
            '/': 2, 
            '^': 3 
        };
        const tokenList = this.formulaToToken()
        const result = []
        const operatorStack = []
        for (const token of tokenList) {
            // 如果是运算符
            if(this.isOperator(token)) {
                while (operatorStack.length > 0 && operatorRank[token] <= operatorRank[operatorStack[operatorStack.length - 1]]) {
                    const operator = operatorStack.pop()
                    result.push(operator)
                }
                operatorStack.push(token)
            } else if (token === '(') {
                operatorStack.push(token)
            } else if (token === ')') {
                while (operatorStack[operatorStack.length - 1] !== '(') {
                    const operator = operatorStack.pop()
                    result.push(operator)
                }
                operatorStack.pop()
            } else {
                result.push(token)
            }
        }
        while (operatorStack.length > 0) {
            result.push(operatorStack.pop())
        }
        return result
    }
    // 是否是运算符
    isOperator(str) {
        const operatorReg = /[+\-/\*\^]/;
        return operatorReg.test(str)
    }
    // 运算符到实际操作映射
    calculator(num1, num2, operator) {
        const calculators = {
            '+': (num1, num2) => (num1 + num2),
            '-': (num1, num2) => (num1 - num2),
            '*': (num1, num2) => (num1 * num2),
            '/': (num1, num2) => (num1 / num2),
            '^': (num1, num2) => (Math.pow(num1, num2))
        }
        return calculators[operator](num1, num2)
    }
    // 计算后缀表达式
    calPostfix() {
        console.log('rpn', this.toPostfix())
        const tokenList = this.toPostfix()
        const numarr = []
        for (const token of tokenList) {
            if (this.isOperator(token)) {
                const num2 = numarr.pop()
                const num1 = numarr.pop()
                const res = this.calculator(num1, num2, token)
                numarr.push(res)
            } else {
                numarr.push(this.params[token])
            }
        }
        console.log(numarr[0])
        return numarr[0]
    }

}


const formula = '((a + b -c) * d / f) ^ g'
let params = {
    a: 2,
    b: 2,
    c: 3,
    d: 5,
    f: 1,
    g: 2,
    h: 3,
}

new CalFormula(formula, params).calPostfix()
posted @ 2022-07-28 16:10  樱风凛  阅读(1242)  评论(0编辑  收藏  举报