package cn.skyatom.common; import java.math.BigDecimal; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * 基础四则运算 * * @author ZWK */ public class Arithmetic { private static String getUUID() { return java.util.UUID.randomUUID().toString().replaceAll("-", ""); } public static void main(String[] args) throws Exception { java.util.Map<String, BigDecimal> values = new java.util.HashMap<String, BigDecimal>(); BigDecimal AAF = new BigDecimal(5.5); BigDecimal BCCC = new BigDecimal(8); BigDecimal QQC = new BigDecimal(-8.33); BigDecimal DCC = new BigDecimal(2); BigDecimal EE = new BigDecimal(23); BigDecimal BF = new BigDecimal(2.5); BigDecimal A1 = new BigDecimal(12); BigDecimal A2 = new BigDecimal(4); BigDecimal A3 = new BigDecimal(5); BigDecimal A4 = new BigDecimal(15); values.put("AAF", AAF); values.put("BCCC", BCCC); values.put("QQC", QQC); values.put("DCC", DCC); values.put("EE", EE); values.put("BF", BF); values.put("A1", A1); values.put("A2", A2); values.put("A3", A3); values.put("A4", A4); // // values.put("B1", 4F); // values.put("B2", 15f); // values.put("B3", 55f); // values.put("B4", 2f); // values.put("B5", 5f); String str = "AAF * BCCC + QQC /DCC-EE*BF+( A1*(A2/(A3+A4)) ) ";//5.5*8 + (-8.33)/2 - 23*2.5 + (12*(4/(5+15)) ) //String str = "B1 * B2 + B3 -B4/ B5 ";//去空白 //BigDecimal v = getArithmeticValue(str, values); System.out.println("结果为:" + getArithmeticFloatValue(str, values)); } /** * 执行运算,获取表达式的结果。float值 * * @param str * @param values * @return * @throws Exception */ public static float getArithmeticFloatValue(String str, java.util.Map<String, BigDecimal> values) throws Exception { return getArithmeticValue(str, values).floatValue(); } public static int getArithmeticIntValue(String str, java.util.Map<String, BigDecimal> values) throws Exception { return getArithmeticValue(str, values).intValue(); } public static long getArithmeticLongValue(String str, java.util.Map<String, BigDecimal> values) throws Exception { return getArithmeticValue(str, values).longValue(); } /** * 替换括号 * * @param str * @param values * @return 当所有替换完成,null,反之返回替换的字符串 */ private static String replaceBrackets(String str, java.util.Map<String, BigDecimal> values) { String v = ""; String tmp = null;//临时字符串值 Pattern patt = Pattern.compile("\\(([A-Za-z0-9\\.\\*\\+\\-/]*?)\\)", Pattern.DOTALL); Matcher mat = patt.matcher(str); if (mat.find()) { tmp = mat.group(1); } if (tmp != null) { String uuid = getUUID(); BigDecimal value = getBasicArithmeticValue(tmp, values); str = str.replace("(" + tmp + ")", uuid); values.put(uuid, value); v = str; v = replaceBrackets(v, values); } else { v = str; } return v; } /** * 执行运算,获取表达式的结果 * * @param str 表达式字符串 * @param values 值存储表 * @return 返回运算值 * @throws java.lang.Exception 运算格式错误时,抛出异常 */ public static BigDecimal getArithmeticValue(String str, java.util.Map<String, BigDecimal> values) throws Exception { str = str.replaceAll("\\s*", "");//去空白 String s = replaceBrackets(str, values); if (s != null || !s.trim().equals("")) { str = s; } return getBasicArithmeticValue(str, values); } /** * 基本四则运算 * * @param str 基础四则运算 * @param values 值存储表 * @return */ private static BigDecimal getBasicArithmeticValue(String str, java.util.Map<String, BigDecimal> values) { str = multiReg(str, values); str = divReg(str, values); java.util.List<Boolean> signs = getPlusReduceSign(str);//获取符号 java.util.List<String> valuesign = getValueSign(str);//替换符号 BigDecimal v = getValue(valuesign, signs, values); return v; } /** * 获取结果 * * @param valuesign 值替换符号 * @param signs 符号 * @param values 值存储表 * @return */ private static BigDecimal getValue(java.util.List<String> valuesign, java.util.List<Boolean> signs, java.util.Map<String, BigDecimal> values) { BigDecimal value = values.get(valuesign.get(0)); for (int i = 0; i < signs.size(); i++) { if (signs.get(i)) { value = value.add(values.get(valuesign.get(i + 1))); //value += values.get(valuesign.get(i + 1)); } else { value = value.subtract(values.get(valuesign.get(i + 1))); //value -= values.get(valuesign.get(i + 1)); } } return value; } /** * 获取替换的符号 * * @param str 待匹配的字符串 * @return 返回 替换的值符号 */ private static java.util.List<String> getValueSign(String str) { java.util.List<String> list = new java.util.ArrayList<String>(); Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1})", Pattern.DOTALL); Matcher mat = patt.matcher(str); while (mat.find()) { if (mat.group(1).trim().equals("")) { continue; } list.add(mat.group(1)); } return list; } /** * 获取加减符号 * * @param str 待匹配的字符串 * @return 返回 符号顺序,加号为true,减号为false */ private static java.util.List<Boolean> getPlusReduceSign(String str) { java.util.List<Boolean> list = new java.util.ArrayList<Boolean>(); Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}([+|-])[a-zA-Z0-9]*{1})", Pattern.DOTALL); Matcher mat = patt.matcher(str); while (mat.find()) { if (mat.group(2).trim().equals("+")) { list.add(true); } else { list.add(false); } } return list; } /** * 乘法的正则 * * @param str 运算表达式字符串 * @param values 值存储表 * @return 返回重构后的字符串 */ private static String multiReg(String str, java.util.Map<String, BigDecimal> values) { Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}\\*[a-zA-Z0-9]*{1})", Pattern.DOTALL); Matcher mat = patt.matcher(str); while (mat.find()) { str = excMultiplication(str, mat.group(1), values); } return str; } /** * 除法的正则 * * @param str 运算表达式字符串 * @param values 值存储表 * @return 返回重构后的字符串 */ private static String divReg(String str, java.util.Map<String, BigDecimal> values) { Pattern patt = Pattern.compile("([a-zA-Z0-9]*{1}\\/[a-zA-Z0-9]*{1})", Pattern.DOTALL); Matcher mat = patt.matcher(str); while (mat.find()) { str = excDivsion(str, mat.group(1), values); } return str; } /** * 计算乘法 * * @param str 全部的运算字符串 * @param value 计算乘法的字符串 * @param map 值存储表 * @return 返回重构后的字符串 */ private static String excMultiplication(String str, String value, java.util.Map<String, BigDecimal> map) { String vs[] = value.split("\\*"); BigDecimal v1 = map.get(vs[0]); BigDecimal v2 = map.get(vs[1]); BigDecimal x = v1.multiply(v2); map.remove(vs[0]); map.remove(vs[1]); String uuid = getUUID(); map.put(uuid, x); str = str.replace(value, uuid); return str; } /** * 计算出发 * * @param str 全部的运算字符串 * @param value 计算乘法的字符串 * @param map 值存储表 * @return 返回重构后的字符串 */ private static String excDivsion(String str, String value, java.util.Map<String, BigDecimal> map) { String vs[] = value.split("\\/"); BigDecimal v1 = map.get(vs[0]); BigDecimal v2 = map.get(vs[1]); BigDecimal x = v1.divide(v2); map.remove(vs[0]); map.remove(vs[1]); String uuid = getUUID(); map.put(uuid, x); str = str.replace(value, uuid); return str; } }
最近在开发公司的绩效系统,老板又很抠门,不想购买市面上的绩效系统。。于是乎,苦逼的我又开始了苦逼的编程……
系统里面涉及到报表,而各员工间的绩效以及实发工资的算法每隔一段时间就会更新,所以不可能做到将算法写进源码编译,需要报表公式进行计算(当然,报表公式系统需要另行开发,这里不描述)。
以上是JAVA代码,其思想是将公式字中的参数当作字符串来看待,并不是当作纯粹的数字。每次运算时,只进行二元运算,运算之后将数据保存,再删除原数据表中的数据。如此循环,无需考虑括号的限制了。
在实现代码时,考虑了直接使用float或者是double类型,但是在最终显示结果是,两个类型精度都会产生精度上的丢失,所以最终考虑使用BigDecimal类型,也算是做长期运行考虑吧。
其中有很多需要优化的地方,敢兴趣的朋友可以留言交流……
本文出自 “Miss-H” 博客,请务必保留此出处http://zwkpc.blog.51cto.com/2281891/1709936
原文地址:http://zwkpc.blog.51cto.com/2281891/1709936