利⽤ScriptEngineManager实现字符串公式灵活计算
在开发中我们可能会遇到好多不固定的公式计算 如有时候我们需要将excel中⼤量的计算公式转换成java语⾔进⾏实现
如果说单纯的⽤java的基本⽅法实现计算 我们就需要的分析excel中的公式将其⼀⼀并转换成java代码 这样对我们开发⼈员来说⼯作量有点太⼤了 ⽽且在转换过程中很可能会出错
下⾯就介绍⼀种简单的实现⽅法
我们知道js的eval()⽅法可以执⾏字符串的代码 ⽽恰好jdk6增加了对脚本语⾔的⽀持 我们可以利⽤这个特性对计算实现简单化的处理
下⾯举个例⼦
加⼊有个公式
A+B*C
A=1,B=2,C=3
我们可以将公式的A B C替换成数字 转换为 1+2*3 最后就可以得到结果了
接下来 我么就探讨下实现⽅法
直接以代吗的形式来写吧
public Double Calculation(String formula){
Double result=null; //计算结果
ScriptEngineManager manager = new ScriptEngineManager(); //创建⼀个ScriptEngineManager对象
ScriptEngine engine = EngineByName("js"); //通过ScriptEngineManager获得ScriptEngine对象
try {
result = (Double) engine.eval(formula); //⽤ScriptEngine的eval⽅法执⾏脚本
} catch (ScriptException e) {
this.isSuccess=false;
result=Double.NaN;
}
return result;
}
利⽤上⾯的⽅法我们就可以将⼀个数学表达式计算出结果
Calculation(“1+2*3”)-->得到结果7
显然这样是不能实现公式的灵活计算的 怎么实现A+B*C 此时我们应该会想到将参数ABC替换成数字就可以实现计算结果了
接下来我们就探讨如何实现替换的功能
说到替换 我们不难想到String的replaceAll⽅法,但是这样我们会遇到⼀个问题就是替换形如A+AA+AAA的问题
如果placeAll("A",2) ;结果就是2+22+222了
所以我想到了利⽤正则去准确匹配替换 ⽅法如下
参数1:替换公式字的符串 参数2: 公式中要替换的字母如上边的A 参数3:要替换成的数值
/**
* 精确替换字符 防⽌出现 匹配A 时将AA匹配的情况
*/
public static String replaceStr(String sourceStr,String replaceKey,String replaceValue){
String replaceStrReg="";
for(char str_CharArray()){
replaceStrReg+="[";
replaceStrReg+=str_char;
replaceStrReg+="]";
}
String startReg="^"+replaceStrReg+"([\\+\\-\\*/,)])";
String endReg="([\\+\\-\\*/,(])"+replaceStrReg+"$";
String reg="([^a-zA-Z])("+replaceStrReg+")"+"([^a-zA-Z])";
String endStr=sourceStr;
while(matcheStr(endStr,replaceKey)){
placeAll(startReg, replaceValue+"$1");
placeAll(reg, "$1"+replaceValue+"$3");
placeAll(endReg, "$1"+replaceValue);
}
return endStr;
}
/**
* 精确匹配字符 防⽌出现 匹配A 时将AA匹配的情况
*/
public static Boolean matcheStr(String sourceStr,String matchStr){
String replaceStrReg="";
for(char str_CharArray()){
replaceStrReg+="[";
replaceStrReg+=str_char;
replaceStrReg+="]";
}
String startReg="^"+replaceStrReg+"([\\+\\-\\*/,)])[\\s\\S]*";
String endReg="[\\s\\S]*([\\+\\-\\*/,(])"+replaceStrReg+"$";
String reg="[\\s\\S]*([^A-Za-z])("+replaceStrReg+")"+"([^A-Za-z])[\\s\\S]*";
if(sourceStr.matches(startReg)||sourceStr.matches(reg)||sourceStr.matches(endReg)){
return true;
}else{
return false;
}
}
上述的正则表达式就是利⽤了数学公式中出现+-*/运算符号的规律
这样我们就可以先替换 再计算了
replaceall()
我们的公式中可以实现计算平⽅等 如Math.pow(2,2) 只要js⽀持的数学公式都可以写进去
⾄于怎么将公式中的参数全部替换 我们可以⽤循环遍历替换参数 这⾥就不写了 有了上⾯的⽅法就ok了
我有这样的想法就是因为开发中频繁编写公式 可能会出错 另⼀⽅⾯纯⽤java实现公式后期维护修改也⿇烦 利⽤这种⽅法我们在后期修改公式时只需修改字符串公式即可
这样我们还可以让⽤户⾃定义公式
当然我们还可以利⽤ScriptEngineManager他实现执⾏js代码块 如if语句等 下⾯是个例⼦ 可以参考下
public Map<String,Object> myFunction(String formula){
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = EngineByName("js");
Object result;
try {
engine.eval(formula);
Invocable inv = (Invocable) engine;
result=inv.invokeFunction("js");
Object function = ("useFunction");
map.put("result", result);
map.put("function", function);
} catch (Exception e) {
result=Double.NaN;
}
return map;
}
⼤家如果有什么好的想法可以与我交流下 共同进步吗
欢迎⼤家与我交流
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论