本例需求:需要在代码中动态计算数学公式(含变量),代码中通过字符串变量替换生成一个数学可执行公式,然后通过调用eval(str)函数计算出结果,由于公式存在除数变量为0的情况,需要对该段表达式进行乘0处理,例如:公式 = a / (b-2),当a=10, b=2时,代入eval('10/(2-2)'),存在除数为0,所以我的处理是通过获取除数表达式(b-2)优先计算,当计算为0时,代入eval('10*0'),相当于把公式替换成:a * 0,需要用到方法如下:
1、校验数学公式方法
/**
* 校验数学公式是否正确
* @param 公式字符串
* @returns true: 正确、false-错误
*/
function checkFormula(str) {
try {
var tmp = str.replace(/[a-zA-Z]+[0-9]*/g, 10);
eval(tmp);
return true;
} catch(err) {
return false;
}
}
2、递归获取所有除数
/**
* 获取数学公式中的所有除数,如果有存在/(..)/..情况,也算一个组合除数
* @param str 数学公式字符串
* @param pattern 正则表达式
* @param divisorArr 返回的所有除数数组
*/
function listDivisor(str, pattern, divisorArr) {
var arr = str.match(new RegExp(pattern, 'g'));
if(arr && arr.length > 0){
$.each(arr, function (i, s) {
s = s.substring(1); //排除第一个/符号
divisorArr.push(s); //添加到数组中,可能存在异常公式,后面会进行统一校验处理
//如果除数是被()包含的运算,存在/(..)/..情况,则获取单个有效除数,采用堆栈形式
if(s.indexOf("(") == 0){
var stock = []; //当stock.length == 0时,说明( == )数量
var tmp1 = "";
var tmp2 = "";
for(var j = 0; i < s.length; j++){
if("(" == s[j]){
stock.push(s[j]);
}
if(")" == s[j]){
stock.pop();
}
if(stock.length == 0){ //找到除数
tmp1 = s.substring(0, j+1);
break;
}
}
divisorArr.push(tmp1);
if(tmp1.length < s.length){
tmp2 = s.substring(tmp1.length, s.length);
}
if(tmp1 && tmp1.indexOf("/") != -1){
listDivisor(tmp1, pattern, divisorArr);
}
if(tmp2 && tmp2.indexOf("/") != -1){
listDivisor(tmp2, pattern, divisorArr);
}
}
});
}
}
3、测试
//测试
function main() {
// var divisorArr1 = []; //缓存不含括号的除数
var divisorArr2 = []; //缓存所有情况的除数
var divisorArr3 = []; //最后返回的除数结果
var formula = "60+a/b+a/((240+c/d*2-1)+(a-a/(c-2+c/(f-2))))/(y-1/(z-1))";
var pattern = "\\/\\(.+\\)|\\/[a-zA-z]+[0-9]*"; //获取含括号的除数正则表达式
// var pattern1= "\\/\\([a-zA-Z0-9\\+\\-\\*\\/]+\\)|\\/[a-zA-z]+[0-9]*"; //获取不含括号的除数正则表达式
//数学公式校验成功则进行除数获取
if(formula && checkFormula(formula)){
listDivisor(formula, pattern, divisorArr2); //递归获取
if(divisorArr2 && divisorArr2.length > 0){
$.each(divisorArr2, function (j, s2) {
if(!divisorArr3.contains(s2) && checkFormula(s2)){
divisorArr3.push(s2);
}
});
}
//排序,按照字符长度从小到大
divisorArr3.sort(function (a, b) {
return a.length - b.length;
});
console.log(divisorArr3.join(","));
}else {
console.log("公式语法错误,请检查!");
return;
}
}
注意:代码仅测试了一些公式表达式,如果存在问题,欢迎大家指正!!!