如何处理数学表达式(一般是字符串型的),如:(1+2*3/4+5+(6*7)/8)。
处理思路:
1、将表达式转换为后缀表达式(也称为逆波兰表达式);
2、计算后缀表达式。
想了解后缀表达式,请参考百度百科:后缀表达式百度百科
import java.util.HashMap; import java.util.Map; import java.util.Stack; public class StackDemo { private static Map<String, Character> OPER_CHAR_MAP = null; public static double calMathExpression(String expression) throws Exception { expression = expression.trim().replaceAll(" ", ""); System.out.println(convertToRPN(expression)); return calRPN(convertToRPN(expression)); } /** * 初始化四则运算符map +、-、*(×)、/(÷) () */ private static void initOperCharMap() { if (OPER_CHAR_MAP == null || OPER_CHAR_MAP.isEmpty()) { OPER_CHAR_MAP = new HashMap<>(); Character additon = new Character("+", 0); Character subtraction = new Character("-", 0); Character multiplication = new Character("*", 1); Character division = new Character("/", 1); Character left_bracket = new Character("(", 2); Character right_bracket = new Character(")", 2); OPER_CHAR_MAP.put("+", additon); OPER_CHAR_MAP.put("-", subtraction); OPER_CHAR_MAP.put("×", multiplication); OPER_CHAR_MAP.put("*", multiplication); OPER_CHAR_MAP.put("÷", division); OPER_CHAR_MAP.put("/", division); OPER_CHAR_MAP.put("(", left_bracket); OPER_CHAR_MAP.put(")", right_bracket); additon = null; subtraction = null; multiplication = null; division = null; left_bracket = null; right_bracket = null; } } /** * 把标准四则表达式转为后缀表达式,以" "分隔每个数字 */ private static String convertToRPN(String expression) throws Exception { StringBuffer rpn_expression = new StringBuffer(); Stack<Character> char_stack = new Stack<>(); // 表达式按照每个字符拆分,考虑多位数,因此在遇到运算符前,用temp累计 StringBuffer temp = new StringBuffer(); // "(" 出现的次数 int left_bracket_cnt = 0; for (int i = 0; i < expression.length(); i++) { String s = expression.substring(i, i + 1); if (isOperationalCharacter(s) != null || i == expression.length() - 1) { try { // 输出temp中的数字 if (temp.length() > 0) { double num = Double.parseDouble(temp.toString()); rpn_expression.append(num); // 分隔符 rpn_expression.append(" "); // 初始化temp temp = new StringBuffer(); } // 输出运算符 Character c = OPER_CHAR_MAP.get(s); if (char_stack.isEmpty()) { char_stack.push(c); } else { switch (c.getValue()) { case "(": // "("直接入栈,等匹配后面的"(" char_stack.push(c); left_bracket_cnt++; break; case "*": case "/": case "+": case "-": // 如果当前的运算不优先于栈顶的,则出栈。"( )"除外 while (!char_stack.isEmpty() && !c.isPrioritizeThen(char_stack.peek()) && !char_stack.peek().value.equals("(")) { rpn_expression.append(char_stack.pop().value); rpn_expression.append(" "); } // 当前运算符入栈 char_stack.push(c); break; case ")": // 依次输出"("前所有的运算符 if (left_bracket_cnt != 0) { while (!char_stack.peek().value.equals("(")) { rpn_expression.append(char_stack.pop().value); rpn_expression.append(" "); } // 移除栈顶的"(" char_stack.pop(); } break; default: break; } } } catch (NumberFormatException e) { throw new NumberFormatException("不支持的运算符或数字"); } catch (Exception e) { throw new Exception("表达式格式不正确"); } } else { temp.append(s); } } return rpn_expression.toString(); } /** * 判断字符串是否为标准四则运算符 +、-、*(×)、/(÷) * * @param str * @return */ private static String isOperationalCharacter(String str) { initOperCharMap(); str = str.trim(); if (OPER_CHAR_MAP.containsKey(str)) { return str; } else { return null; } } /** * 计算后缀表达式 * * @return */ private static double calRPN(String rpn_expression) { String[] characters = rpn_expression.split(" "); Stack<Double> char_stack = new Stack<>(); for (int i = 0; i < characters.length; i++) { if (isOperationalCharacter(characters[i]) == null) { char_stack.push(Double.parseDouble(characters[i])); } else { double first = char_stack.pop(); double second = char_stack.pop(); switch (characters[i]) { case "*": char_stack.push(first * second); break; case "/": char_stack.push(second / first); break; case "+": char_stack.push(first + second); break; case "-": char_stack.push(second - first); break; default: break; } } } return char_stack.pop(); } /** * 四则运算符 * * @author kevingcang * */ static class Character { /** * 值 */ private String value; /** * 优先级 */ private int priority; public Character(String value, int priority) { super(); this.value = value; this.priority = priority; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public int getPriority() { return priority; } public void setPriority(int priority) { this.priority = priority; } public boolean isPrioritizeThen(Character chr) { if (this.priority > chr.priority) { return true; } else { return false; } } } public static void main(String[] args) { String str = "(1+2*3/4+5+(6*7)/8)"; try { System.out.println(StackDemo2.calMathExpression(str)); } catch (Exception e) { e.printStackTrace(); } } }
四则表达式转后缀表达式、后缀表达式的计算主要借助栈来实现。原表达式为:(1+2*3/4+5+(6*7)/8) 转换为后缀表达式后 1 2 3 * 4 / + 5 + 6 7 * 8 / + 计算结果为:12.75。为方便数据用的double类型。