利用ScriptEngineManager实现字符串公式灵活计算的方法

网友投稿 526 2023-01-25


利用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 = manager.getEngineByName("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的问题

如果str.replaceAll("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_char:replaceKey.toCharArray()){

replaceStrReg+=http://"[";

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)){

endStr=endStr.replaceAll(startReg, replaceValue+"$1");

endStr=endStr.replaceAll(reg, "$1"+replaceValue+"$3");

endStr=endStr.replaceAll(endReg, "$1"+replaceValue);

}

return endStr;

}

/**

* 精确匹配字符 防止出现 匹配A 时将AA匹配的情况

*/

public static Boolean matcheStr(String sourceStr,String matchStr){

String replaceStrReg="";

for(char mJwGYstr_char:matchStr.toCharArray()){

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;

}

}

上述的正则表达式就是利用了数学公式中出现+-*/运算符号的规律

这样我们就可以先替换 再计算了

我们的公式中可以实现计算平方等 如Math.pow(2,2) 只要js支持的数学公式都可以写进去

至于怎么将公式中的参数全部替换 我们可以用循环遍历替换参数 这里就不写了 有了上面的方法就ok了

我有这样的想法就是因为开发中频繁编写公式 可能会出错 另一方面纯用java实现公式后期维护修改也麻烦 利用这种方法我们在后期修改公式时只需修改字符串公式即可

这样我们还可以让用户自定义公式

当然我们还可以利用ScriptEngineManager他实现执行js代码块 如if语句等 下面是个例子 可以参考下

public Map myFunction(String formula){

ScriptEngineManager manager = new ScriptEngineManager();

ScriptEngine engine = manager.getEngineByName("js");

Object result;

try {

engine.eval(formula);

Invocable inv = (Invocable) engine;

result=inv.invokeFunction("js");

Object function = engine.get("useFunction");

map.put("result", result);

map.put("function", function);

} catch (Exception e) {

result=Double.NaN;

}

return map;

}


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java判断List中有无重复元素的方法
下一篇:内存共享文件系统怎么设置(win7共享内存设置)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~