前一段时间,为了满足公司的web报表系统的需求,利用javascript开发了一个自定义公式解析计算器。开发人员可以根据一定规则,自定义web页面元素或者json字段之间的公式关系,实现算术运算和一些逻辑运算。
另外,还对页面的输入,数据的有效位数等进行了处理,每个数据字段的有效位数,开发人员都可以自定义。
该公式解析计算器的具体使用的例子,在我另外一篇博客文章中(http://huangyuanmu.iteye.com/admin/blogs/469180),有兴趣的话,可以看看。
下边给出具体实现代码:
/** * 模拟java的包,或者C#中的命名空间的概念 * */ var tohot = tohot ? tohot : {}; tohot.commons = tohot.commons ? tohot.commons : {}; tohot.commons.declaration = tohot.commons.declaration ? tohot.commons.declaration : {}; /** * 报表公式计算器实现 */ var tohotCalculator = tohot.commons.declaration.ExpressionCalculator = tohot.commons.declaration.ExpressionCalculator ? tohot.commons.declaration.ExpressionCalculator : { description : "通用web报表公式解析计算器,根据自定义的报表计算公式,自动进行公式解析和报表数据计算,操作web报表页面数据和json数据。", author : "huangyuanmu", version : "1.0(2009-07-29)", report : {}, // 根据公式,获取计算以后的值 getValue : function(report,formular_str,dataType) { // 解析公式 function _parseFormular() { if (mathing_begin) { mathing_str += formular_str.substr(i,1); return true; } else { if (IsVar) { formular_str_ana += ")"; CurVar_Length += ")".length; //判断当前的变量的值是否为空 tmpEl = eval(formular_str_ana.substr(CurVar_start,CurVar_Length)); if (isNaN(tmpEl)) { formular_str_ana = formular_str_ana.substr(0,CurVar_start); formular_str_ana += "0"; } } formular_str_ana += formular_str.substr(i,1); IsVar = false; return true; } return false; } var formular_str_ana; var returnValue; var IsVar; //表示该处的字符表示变量 var CurVar_start,CurVar_Length; //表示当前的变量型字符串 var mathing_begin = false; //字符串的匹配操作是否开始 var mathing_str = ""; //接受并解析匹配字符串 returnValue = 0; IsVar = false; var el_chang = "report."; formular_str_ana = ""; if(dataType == null){ dataType = "2"; } for (i = 0;i<formular_str.length;i++) { switch(formular_str.substr(i,1)) { case "$": { if (mathing_begin) { mathing_str += formular_str.substr(i,1); break; } else { //变量的开始 CurVar_start = formular_str_ana.length; formular_str_ana += "parseFloat(" + el_chang; CurVar_Length = ("parseFloat(" + el_chang).length; IsVar = true; break; } } case "@": { //匹配字符串的解释 if (mathing_begin) { //匹配字符串结束 mathing_begin = false; mathing_str_arr = mathing_str.split(";"); formular_str_ana += "/^" + mathing_str_arr[0] + "$/i.test("; if (mathing_str_arr[1].substr(0,1) == "$") { formular_str_ana += "report" + "." + mathing_str_arr[1].substr(1,mathing_str_arr[1].length-1) + ")"; } else { //非变量 formular_str_ana += "'" + mathing_str_arr[1].substr(0,mathing_str_arr[1].length) + "')"; } } else { //匹配字符串开始 mathing_begin = true; mathing_str = ""; } break; } case "+": { if(_parseFormular()) { break; } } case "-": { if(_parseFormular()) { break; } } case "*": { if(_parseFormular()) { break; } } case "/": { if(_parseFormular()) { break; } } case "%": { if(_parseFormular()) { break; } } case ")": { if(_parseFormular()) { break; } } case "?": { if(_parseFormular()) { break; } } case ":": { if(_parseFormular()) { break; } } case "<": { if(_parseFormular()) { break; } } case "=": { if(_parseFormular()) { break; } } case ">": { if(_parseFormular()) { break; } } case "!": { if(_parseFormular()) { break; } } case "|": { if(_parseFormular()) { break; } } case "&": { if(_parseFormular()) { break; } } default: { if (mathing_begin) { mathing_str += formular_str.substr(i,1); break; } else { if (IsVar) { CurVar_Length++; } formular_str_ana += formular_str.substr(i,1); } } } } if (IsVar) { formular_str_ana += ")"; CurVar_Length += ")".length; //判断当前的变量的值是否为空 tmpEl = eval(formular_str_ana.substr(CurVar_start,CurVar_Length)); if (isNaN(tmpEl)) { formular_str_ana = formular_str_ana.substr(0,CurVar_start); formular_str_ana += "0"; } IsVar = false; } if (mathing_begin) { //匹配字符串结束 mathing_begin = false; mathing_str_arr = mathing_str.split(","); formular_str_ana += "/" + mathing_str_arr[0] + "/i.test("; if (mathing_str_arr[1].substr(0,1) == "$") { formular_str_ana += "report" + "." + mathing_str_arr[1].substr(1,mathing_str_arr[1].length-1) + ")"; } else { //非变量 formular_str_ana += "'" + mathing_str_arr[1].substr(0,mathing_str_arr[1].length) + "')"; } } returnValue = eval(formular_str_ana); // 如果公式计算的值小于0.005,则认为为零 if (Math.abs((returnValue - 0.00))<0.005) { returnValue = tohotCalculator.formatData("0",dataType); }else{ returnValue = tohotCalculator.formatData(returnValue + "",dataType); } return returnValue; }, // 格式化整数 formatInteger: function (IntegerStr){ //获取字符串的长度和首字符和次字符,然后进行判断 var strLen = IntegerStr.length; var firstStr = IntegerStr.substr(0,1); var secondStr = IntegerStr.substr(1,1); var tmpStr = IntegerStr; //针对正数的处理 if(firstStr != "-"){ if ((firstStr == "0") && (strLen > 1)){ tmpStr = tmpStr.substr(1,strLen-1); tmpStr = tohotCalculator.formatInteger(tmpStr); } } else{ //负数的处理 if((secondStr == "0") && (strLen > 2)){ tmpStr = "-" + tmpStr.substr(2,strLen-2); tmpStr = tohotCalculator.formatInteger(tmpStr); } } return tmpStr; }, // 格式化浮点数 formatFloat: function (FloatStr){ //将字符串组合成整数部分和小数部分 var FloatStrArr = FloatStr.split("."); var Integer_part = FloatStrArr[0]; var Float_part = FloatStrArr[1]; var FloatPartLen = Float_part.length; //处理整数部分 if((Integer_part == "-") || (Integer_part == "")){ Integer_part += "0"; } Integer_part = tohotCalculator.formatInteger(Integer_part); //处理小数部分 if(FloatPartLen == 0){ Float_part += "00"; } else{ if(FloatPartLen == 1){ Float_part += "0"; } } //合并 return (Integer_part + "." + Float_part); }, // 数据验证,并设置json对象元素的值 formatData: function (DataStr,DataType){ var returnValue = "0.00"; var IntegerCode,FloatCode;//数字的整数验证码和小数验证码 IntegerCode = /^[-]?[0-9]+$/i; //整数 FloatCode = /^[-]?[0-9]*[.][0-9]+$/i; //整数 if (DataStr != ""){ if(DataType == "1") { if (DataStr.match(IntegerCode) == null) { if ((DataStr.match(FloatCode) == null)) { returnValue = "0"; } else{ var reVal = parseFloat(tohotCalculator.formatFloat(DataStr)); returnValue = ""+reVal.toFixed(0); } } else{ returnValue = tohotCalculator.formatInteger(DataStr); } } else if((DataType == "2") || (DataType == "3") || (DataType == "4")) { if (DataStr.match(IntegerCode) == null) { if ((DataStr.match(FloatCode) == null)) { if(DataType == "2") returnValue = "0.00"; if(DataType == "3") returnValue = "0.0000"; if(DataType == "4") returnValue = "0.000000"; } else{ var reVal = parseFloat(tohotCalculator.formatFloat(DataStr)); returnValue = reVal.toFixed(parseInt(DataType)+ (parseInt(DataType) - 2)); } } else{ if(DataType == "2") returnValue = tohotCalculator.formatInteger(DataStr + ".00"); if(DataType == "3") returnValue = tohotCalculator.formatInteger(DataStr + ".0000"); if(DataType == "4") returnValue = tohotCalculator.formatInteger(DataStr + ".000000"); } }else{ returnValue = "0.00"; } }else{ if(DataType == "1"){ returnValue = "0"; }else if(DataType == "2"){ returnValue = "0.00"; }else if(DataType == "3"){ returnValue = "0.0000"; }else if(DataType == "4"){ returnValue = "0.000000"; }else{ returnValue = "0.00"; } } return returnValue; }, doCalculateFormular : function (formular) { var formualr_is_arr = /[,]/i; //解析公式 if (formular.match(formualr_is_arr) == null) { //单个公式 each_formular_arr = formular.split("^"); // 解析目标json值的有效位数 var targetArray = each_formular_arr[1].split("#"); // 设置报表json对象的值 var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); // 设置页面元素的值 var el = eval(each_formular_arr[0]); el.value = value; } else { //公式数组 all_formular_arr = formular.split(","); for (k=0;k<all_formular_arr.length;k++) { //单个公式 each_formular_arr = all_formular_arr[k].split("^"); // 解析目标json值的有效位数 var targetArray = each_formular_arr[1].split("#"); // 设置报表json对象的值 var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); // 设置页面元素的值 var el = eval(each_formular_arr[0]); el.value = value; } } }, // 计算整个json报表对象,在保存报表的时候调用 doCalculateJson : function (reportFormular) { _calculatorJson(reportFormular); // 计算报表json对象的公式触发 function _calculatorJson(reportFormular) { var EachArrStr = ""; var FoumularArr; //公式数组 var formualr_is_arr = /[,]/i; var e1; //解析公式 for(key in reportFormular){ formular = reportFormular[key]; if (formular.match(formualr_is_arr) == null) { //单个公式 each_formular_arr = formular.split("^"); // 解析目标json值的有效位数 var targetArray = each_formular_arr[1].split("#"); var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); } else { //公式数组 all_formular_arr = formular.split(","); for (k=0;k<all_formular_arr.length;k++) { //单个公式 each_formular_arr = all_formular_arr[k].split("^"); // 解析目标json值的有效位数 var targetArray = each_formular_arr[1].split("#"); var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); } } } } }, // 根据公式计算当前页面的表单元素的值,在页面onblur事件的时候调用 doCalculateCurr : function (cur_el_name,el_value,formular,DataType){ _calculatorCurr(cur_el_name,el_value,formular,DataType); // 计算当前页面的公式触发 function _calculatorCurr(cur_el_name,el_value,formular,DataType) { var EachArrStr = ""; var FoumularArr; //公式数组 var formualr_is_arr = /[,]/i; var e1; if(_dataAuth(cur_el_name,el_value,DataType)) { //解析公式 if (formular.match(formualr_is_arr) == null) { //单个公式 each_formular_arr = formular.split("^"); // 解析目标单元格的有效位数 var targetArray = each_formular_arr[1].split("#"); // 设置报表json对象的值 var form_el_value = tohotCalculator.formatData(el_value,DataType); eval("tohotCalculator.report." + cur_el_name + "=form_el_value"); var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); // 设置页面元素的值 var el = eval(each_formular_arr[0]); el.value = value; } else { //公式数组 all_formular_arr=formular.split(","); for (k=0;k<all_formular_arr.length;k++) { //单个公式 each_formular_arr = all_formular_arr[k].split("^"); // 解析目标单元格的有效位数 var targetArray = each_formular_arr[1].split("#"); // 设置报表json对象的值 var form_el_value = tohotCalculator.formatData(el_value,DataType); eval("tohotCalculator.report." + cur_el_name + "=form_el_value"); var value = tohotCalculator.getValue(tohotCalculator.report,targetArray[0],targetArray[1]); eval("tohotCalculator.report." + each_formular_arr[0] + "=value"); // 设置页面元素的值 var el = eval(each_formular_arr[0]); el.value = value; } } } } // 数据验证,并设置页面元素的值 function _dataAuth(DataStr_el_name,DataStr,DataType){ var DataStr_el = eval(DataStr_el_name); DataStr_el.value = tohotCalculator.formatData(DataStr,DataType); return true; } } }