js解析数学运算公式


已上传到npm,NPM包地址:

https://www.npmjs.com/package/exec-mathexpress

//运行demo

const execMathExpress=require('./utils/execMathExpress');

//贝叶斯 条件概率公式 SW=WS*S/(WS*S+WH*H);(只用于二分类)
console.log(execMathExpress('WS*S/(WS*S+WH*H)',{
WS:'1/2',
S:'1/4',
WH:'1/2',
H:'3/4'
}))
//->Fraction { num: 1, den: 4 }

//贝叶斯联合概率公式(只用于二分类)
console.log(execMathExpress('P0*P1*P2/(P0*P1*P2+(1-P0)*(1-P1)*(1-P2))',{ P0: '1/2', P1: '2/3', P2: '3/4' }))
//->Fraction { num: 6, den: 7 }


源码:execMathExpress.js
//欧几里得算法 求两个数a、b的最大公约数
function gcd(a,b){
    return b===0?a:gcd(b,a%b)
}
//分数类 分子,分母
class Fraction{
    static create(num,den=1) {
        if(num instanceof Fraction){
            return num;
        }else if(/(-?d+)/(d+)/.test(num)){
            return new Fraction(parseInt(RegExp.$1),parseInt(RegExp.$2))
        }else{
            if(/.(d+)/.test(num)){
                num=num*Math.pow(10,RegExp.$1.length);
                den=den*Math.pow(10,RegExp.$1.length);
            }
            if(/.(d+)/.test(den)){
                num=num*Math.pow(10,RegExp.$1.length);
                den=den*Math.pow(10,RegExp.$1.length);
            }
            return new Fraction(num,den)
        }
    }
    constructor(num=0,den=1){
        if(den<0){
            num=-num;
            den=-den;
        }
        if(den===0){
            throw '分母不能为0'
        }
        let g=gcd(Math.abs(num),den)
        this.num=num/g;
        this.den=den/g;
    }
    //
    add(o){
        return new Fraction(this.num*o.den+this.den*o.num,this.den*o.den)
    }
    //
    sub(o){
        return new Fraction(this.num*o.den-this.den*o.num,this.den*o.den)
    }
    //
    multiply(o){
        return new Fraction(this.num*o.num,this.den*o.den);
    }
    //
    divide(o){
        return new Fraction(this.num*o.den,this.den*o.num);
    }
    //小于
    lessThan(o){
        return this.num*o.den<this.den*o.num;
    }
    //等于
    equal(o){
        return this.num*o.den===this.den*o.num;
    }
    toString() {
        return this.num+'/'+this.den;
    }
}

//解析数学表达式
function execMathExpress(formula,obj){
    //局部变量
    const tempObj=Object.assign({
        _0:0
    },obj);
    //计算缓存
    const keyCache={};
    let index=1;

    formula=formula.replace(/ /g,'');//清理空格
    //解析数字
    formula=formula.replace(/(^|[(*+/-])(d+.d+|d+)/g,function (m,p1,p2) {
        if(keyCache[p2]){
            return p1+keyCache[p2];
        }
        const key=keyCache[p2]='_'+index++;
        tempObj[key]=Fraction.create(p2);
        return p1+key;
    })

    function getKey(p1,p2,p3) {
        const keyC=p1+p2+p3;
        if(keyCache[keyC]){
            return keyCache[keyC];
        }
        const key=keyCache[keyC]='_'+index++;
        const fA=Fraction.create(tempObj[p1])
        const fB=Fraction.create(tempObj[p3])
        if(p2==='*'){
            tempObj[key]=fA.multiply(fB);
        }else if(p2==='/'){
            tempObj[key]=fA.divide(fB);
        }else if(p2==='+'){
            tempObj[key]=fA.add(fB);
        }else if(p2==='-'){
            tempObj[key]=fA.sub(fB);
        }
        return key;
    }
    function run(s) {

        //子表达式
        if(/(([^(]+?))/.test(s)){
            s=s.replace(/(([^(]+?))/g,function (m,p1,p2) {
                return run(p1);
            })
        }
        //负号
        s=s.replace(/([*/+]|^)-(w+)/g,function (m,p1,p2) {
            return getKey('_0','-',p2);
        })
        //返回
        if(/(^w+$)/.test(s)){
            return RegExp.$1;
        }
        //乘法、除法、加法、减法
        const expArr=['*','/','+','-'];
        for(let i=0;i<expArr.length;i++){
            const p=expArr[i];
            const reg=new RegExp('(\w+)['+p+'](\w+)');
            while (reg.test(s)){
                s=s.replace(reg,function (m,p1,p2) {
                    return getKey(p1,p,p2);
                })
            }
        }
        //返回
        if(/(^w+$)/.test(s)){
            return RegExp.$1;
        }
        return run(s);
    }
    return tempObj[run(formula)]
}
module.exports=execMathExpress;
原文地址:https://www.cnblogs.com/caoke/p/11053253.html