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

 更新时间:2018年07月18日 09:31:23   作者:wyzdeng  
今天小编就为大家分享一篇利用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+="[";
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 str_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<String,Object> 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;
}

以上这篇利用ScriptEngineManager实现字符串公式灵活计算的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • 详解Java中的Lambda表达式

    详解Java中的Lambda表达式

    Lambda表达式是Java SE 8中一个重要的新特性。这篇文章主要介绍了Java中的Lambda表达式 ,需要的朋友可以参考下
    2019-04-04
  • java synchronized实现可见性过程解析

    java synchronized实现可见性过程解析

    这篇文章主要介绍了java synchronized实现可见性过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • 浅谈使用Java Web获取客户端真实IP的方法示例详解

    浅谈使用Java Web获取客户端真实IP的方法示例详解

    这篇文章主要介绍了使用Java-Web获取客户端真实IP的方法示例详解。一般我们无法获取客户端真实IP,原因是:当我们通过request获取客户端IP时,自身服务器通常会为了保护信息或者负载均衡的目的,对自身服务器做反向代理。对此感兴趣可以了解一下
    2020-07-07
  • Java面试之SQL语句题经典案例

    Java面试之SQL语句题经典案例

    本文详细讨论了如何将行数据转化为列数据,并提供了多种SQL查询练习题,包括查询特定条件的学生信息、课程成绩比较、学生成绩排名等,文章还解释了在SQL中使用Union、UnionAll和pivot的方法,以及如何处理复杂的SQL查询问题,需要的朋友可以参考下
    2024-10-10
  • spring使用aspect注解切面不起作用的排查过程及解决

    spring使用aspect注解切面不起作用的排查过程及解决

    这篇文章主要介绍了spring使用aspect注解切面不起作用的排查过程及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-06-06
  • Java 垃圾回收机制详解及实例代码

    Java 垃圾回收机制详解及实例代码

    这篇文章主要介绍了 Java 垃圾回收机制详解及实例代码的相关资料,需要的朋友可以参考下
    2017-02-02
  • Java 如何实现一个http服务器

    Java 如何实现一个http服务器

    这篇文章主要介绍了Java 如何实现一个http服务器,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下
    2020-11-11
  • springboot + mybatis-plus实现多表联合查询功能(注解方式)

    springboot + mybatis-plus实现多表联合查询功能(注解方式)

    这篇文章主要介绍了springboot + mybatis-plus实现多表联合查询功能,是最简单的一种注解方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • OpenFeign实现远程调用

    OpenFeign实现远程调用

    这篇文章主要为大家详细介绍了OpenFeign实现远程调用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • 关于Spring @Transactional事务传播机制详解

    关于Spring @Transactional事务传播机制详解

    我们日常工作中极少使用事务传播级别,单纯只是使用事务和rollbackfor抛出异常来解决事务问题,但其实我们很多时候使用的是不正确的,或者说会造成事务粒度过大,本文详解一下事务传播级别,也让自己更好地处理事务问题,需要的朋友可以参考下
    2023-08-08

最新评论