利用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实现字符串公式灵活计算的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持脚本之家。
- ASP.NET MVC 2示例Tailspin Travel UI层分析
- CSS 命名之Dialog, Modal, Popup, Popover, Lightbox 等的区别
- Eclipse JAVA文件注释乱码
- 2018年小程序的红利趋势预测,懂的来……或许你将成为下个富翁
- VUE 入门基础(6)
- 五年换4高管,6000员工裁95%剩300人,王健林为何抛弃万达网科?
- Android Permission中英对照
- 你知道人脸识别技术是如何实现的吗?
- WordPress REST API 定制化输出
- ASP.NET MVC的Action Filter
- Android LayoutInflater详解
- 在Android中实现service动态更新UI界面
- VUE 入门基础(5)
- Android的UI设计与后台线程交互
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 从零开始学习华为路由交换 | OSPF修改计时器
- 【没落的985/211】Python爬取知乎8万字回答进行高校分析
- LinkedBlockingQueue源码学习
- 三歪吐血总结了各个中间件是如何实现持久化的
- ThreadPoolExecutor源码学习
- Docker六脉神剑(四) 使用Docker-Compose进行服务编排搭建lnmp环境
- 干的想喝水,一篇文章带你读懂硬盘工作原理!
- 微信小程序开发实战(11):滚动组件(picker)
- Docker六脉神剑 (五) Docker Swarm集群搭建及基础服务部署
- 思科模拟器GNS3将路由器变成交换机的方法
- docker安装nginx并配置https
- Docker Swarm集群部署lnmp+redis
- Maven快速入门
- TomCat安装及快速部署
- SpringCloud+MyBatis分页处理(前后端分离)