需求很简单,给定一个字符串形式的公式规则,用java代码进行拆解,并能计算出结果。
♦考虑字符串中数字格式【整数、小数点】
♦考虑字符串中运算符【+-*/()】
♦考虑空格、运算规则【被0除】
以下是参考地址,里边有讨论部分的内容:
https://bbs.csdn.net/topics/380022283
下边是代码部分,可以作为一个工具类进行使用:
package test; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Stack; /** * 给定公式字符串拆解计算 * @author kerala * */ public class CalUtil { static final String symbol = "+-*/()"; //运算符 static final String[] priority = {"+-", "*/", "()"}; //运算符优先级 /** * 运算符比较器 */ static Comparator<String> comp = new Comparator<String>() { public int compare(String s1, String s2) { int n1=0, n2=0; for (int i=0; i<priority.length; i++) { if (priority[i].indexOf(s1) >= 0) {n1 = i;} if (priority[i].indexOf(s2) >= 0) {n2 = i;} } return (n1 - n2); } }; /** * 输入字符串公式,返回结果 * @param exp * @return * @throws Exception */ public static String getResultByStrCal(String exp) throws Exception{ List<String> list = analyze(exp); //中缀转后缀 double result = cacl(list); //计算结果 return String.format("%.2f", result);//%.2f 解释:%f ——浮点型 .2 ——两位小数点 ——换行 } /** * 分析算式 * @param exp * @return * @throws Exception */ public static List<String> analyze(String exp) throws Exception { if (exp == null) { throw new Exception ("illegal parameter."); } exp = exp.replaceAll("\s*", ""); //去掉所有的空格(为了方便中间存在空格算合法) List<String> list = new ArrayList<String>(); Stack<String> sym = new Stack<String>(); StringBuilder buf = new StringBuilder(); for (char c : exp.toCharArray()) { if (symbol.indexOf(c) >= 0) { //如果是运算符 if (buf.length() > 0) { //如果有操作数 String v = buf.toString(); if (! v.matches("\d+([.]\d+)?")) { throw new Exception ("illegal varaible("+v+")."); } list.add(v); buf.delete(0, buf.length()); } if (c == '(') { sym.push(String.valueOf(c)); } else if (c == ')') { String last = ""; while (sym.size() > 0) { last = sym.pop(); if (last.equals("(")) { break; } else { list.add(last); } } if (!"(".equals(last)) { throw new Exception ("illigal express."); } } else if (sym.size() > 0) { String s = String.valueOf(c); String last = sym.peek(); if (last.equals("(") || comp.compare(s, last) > 0) { sym.push(s); } else { last = sym.pop(); list.add(last); sym.push(s); } } else { sym.push(String.valueOf(c)); } } else { //不是运算符则当作操作数(因为已经去除所有空格,这里不再需要判断空格) buf.append(c); } } if (buf.length() > 0) { list.add(buf.toString()); } while (sym.size() > 0) { String last = sym.pop(); if ("()".indexOf(last) >= 0) { throw new Exception ("illigal express."); } list.add(last); } return list; } /** * 计算 * @param list * @return * @throws Exception */ public static double cacl(List<String> list) throws Exception { Stack<Double> val = new Stack<Double>(); double result = 0; while (list.size() > 0) { String s = list.remove(0); if (symbol.indexOf(s) >= 0) { double d1 = val.pop(); double d2 = val.pop(); if ("+".equals(s)) { result = d2 + d1; } else if ("-".equals(s)) { result = d2 - d1; } else if ("*".equals(s)) { result = d2 * d1; } else if ("/".equals(s)) { result = d2 / d1; } else { throw new Exception ("illigal symbol("+s+")."); } val.push(result); } else { if (!s.matches("\d+([.]\d+)?")) { throw new Exception ("illigal variable("+s+")."); } val.push(Double.valueOf(s)); } } return result; } }
测试一下:
package test; /** * 测试拆分字符串公式运算 * @author kerala * */ public class TestCal { /** * @param args * @throws Exception */ public static void main(String[] args) { String exp = "2.5*0.4+(2*5)"; try { String result = CalUtil.getResultByStrCal(exp); System.out.printf(result); } catch (Exception e) { e.printStackTrace(); System.out.println("请输入正确计算公式"); } } }
目前测试了几个公式,都还正确,如果有问题,以后再补充!