欢迎来到258分享网,纯净的网络源码分享基地!

258资源分享网

全部作品
全部作品
网站源码
微信源码
素材特效
源码插件
视频教程
建站学院
热门搜索: 织梦  农业种植  农业  安全设置  官方
258资源分享 > 建站学院 > MYSQL教程 > 使用java处理字符串公式运算的方法

推荐下载

HTML5响应式自适应网咯设计

2020-05-12   浏览:736

高端HTML5响应式企业通用网

2020-05-06   浏览:517

html5响应式外贸网站英文版

2020-05-08   浏览:505

HTML5自适应律师工作室类网

2020-04-04   浏览:501

HTML5影视传媒文化公司类网

2020-05-12   浏览:494

使用java处理字符串公式运算的方法

发布时间:2020-01-15  
在改进一个关于合同的项目时,有个需求,就是由于合同中非数据项的计算公式会根据年份而进行变更,而之前是将公式硬编码到系统中的,只要时间一变,系统就没法使用了,因此要求合同中各个非基础数据的项都能自定义公式,根据设置的公式来自动生成报表和合同中的数据。     显然定义的公式都是以字符串来存储到数据库的,可是java中没有这种执行字符串公式的工具或者类,而且是公式可以嵌套一个中间公式。比如:基础数据dddd是56,而一个公式是依赖dddd的,eeee=dddd*20,而最终的公式可能是这样:eeee*-12+13-dddd+24。可知eeee是一个中间公式,所以一个公式的计算需要知道中间公式和基础数据。   这好像可以使用一个解释器模式来解决,但是我没有成功,因为括号的优先级是一个棘手的问题,后来又想到可以使用freemarker类似的模板引擎或者java6之后提供的ScriptEngine 脚本引擎,做了个实验,脚本引擎可以解决,但是这限制了必须使用java6及以上的版本。最终功夫不负有心人,终于找到了完美解决方案,即后缀表达式。我们平时写的公式称作中缀表达式,计算机处理起来比较困难,所以需要先将中缀表达式转换成计算机处理起来比较容易的后缀表达式。   将中缀表达式转换为后缀表达式具体算法规则:见后缀表达式     a.若为 '(',入栈;   b.若为 ')',则依次把栈中的的运算符加入后缀表达式中,直到出现'(',从栈中删除'(' ;   c.若为 除括号外的其他运算符 ,当其优先级高于栈顶运算符时,直接入栈。否则从栈顶开始,依次弹出比当前处理的运算符优先级高和优先级相等的运算符,直到一个比它优先级低的或者遇到了一个左括号为止。   ·当扫描的中缀表达式结束时,栈中的的所有运算符出栈;    我们提出的要求设想是这样的:   复制代码 代码如下:     public class FormulaTest { @Test public void testFormula() { //基础数据 Map<String, BigDecimal> values = new HashMap<String, BigDecimal>(); values.put("dddd", BigDecimal.valueOf(56d));   //需要依赖的其他公式 Map<String, String> formulas = new HashMap<String, String>(); formulas.put("eeee", "#{dddd}*20");   //需要计算的公式 String expression = "#{eeee}*-12+13-#{dddd}+24";   BigDecimal result = FormulaParser.parse(expression, formulas, values); Assert.assertEquals(result, BigDecimal.valueOf(-13459.0)); } }     以下就是解决问题的步骤: 1、首先将所有中间变量都替换成基础数据   FormulaParser的finalExpression方法会将所有的中间变量都替换成基础数据,就是一个递归的做法   复制代码 代码如下:     public class FormulaParser { /** * 匹配变量占位符的正则表达式 */ private static Pattern pattern = Pattern.compile("\\#\\{(.+?)\\}");   /** * 解析公式,并执行公式计算 *  * @param formula * @param formulas * @param values * @return */ public static BigDecimal parse(String formula, Map<String, String> formulas, Map<String, BigDecimal> values) { if (formulas == null)formulas = Collections.emptyMap(); if (values == null)values = Collections.emptyMap(); String expression = finalExpression(formula, formulas, values); return new Calculator().eval(expression); }   /** * 解析公式,并执行公式计算 *  * @param formula * @param values * @return */ public static BigDecimal parse(String formula, Map<String, BigDecimal> values) { if (values == null)values = Collections.emptyMap(); return parse(formula, Collections.<String, String> emptyMap(), values); }   /** * 解析公式,并执行公式计算 *  * @param formula * @return */ public static BigDecimal parse(String formula) { return parse(formula, Collections.<String, String> emptyMap(), Collections.<String, BigDecimal> emptyMap()); }   /** * 将所有中间变量都替换成基础数据 *  * @param expression * @param formulas * @param values * @return */ private static String finalExpression(String expression, Map<String, String> formulas, Map<String, BigDecimal> values) { Matcher m = pattern.matcher(expression); if (!m.find())return expression;   m.reset();   StringBuffer buffer = new StringBuffer(); while (m.find()) { String group = m.group(1); if (formulas != null && formulas.containsKey(group)) { String formula = formulas.get(group); m.appendReplacement(buffer, '(' + formula + ')'); } else if (values != null && values.containsKey(group)) { BigDecimal value = values.get(group); m.appendReplacement(buffer,value.toPlainString()); }else{ throw new IllegalArgumentException("expression '"+expression+"' has a illegal variable:"+m.group()+",cause veriable '"+group+"' not being found in formulas or in values."); } } m.appendTail(buffer); return finalExpression(buffer.toString(), formulas, values); } }     2、将中缀表达式转换为后缀表达式   Calculator的infix2Suffix将中缀表达式转换成了后缀表达式   3、计算后缀表达式     Calculator的evalInfix计算后缀表达式   复制代码 代码如下:

本文标签

:备案管家服务帮您把复杂流程变简单,解决您在进行网站备案过程中遇到的效率低下和成功率不高的问题。个人300/2个域名,企业500/5个域名,qq1650004.