java 解析四则混合运算表达式并计算结果

  1. package ch8;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Stack;
  5. /**
  6. * 四则混合运算表达式计算
  7. * @author Jinjichao
  8. *
  9. */
  10. public class Calculator {
  11.     /**
  12.      * 运算符枚举
  13.      * @author Jinjichao
  14.      *
  15.      */
  16.     private enum Operator {
  17.         ADD("+", 10), SUBTRACT("-", 10), MULTIPLY("*", 20), DIVIDE("/", 20),
  18.         PARENTHESIS_LEFT("(", 100), PARENTHESIS_RIGHT(")", 100);
  19.         private String operator;
  20.         private int priority;
  21.         private Operator(String operator, int priority) {
  22.             this.operator = operator;
  23.             this.priority = priority;
  24.         }
  25.     }
  26.     /**
  27.      * 操作数枚举
  28.      * @author Jinjichao
  29.      *
  30.      */
  31.     private enum Operand {
  32.         ONE("1"), TWO("2"), THREE("3"), FOUR("4"), FIVE("5"), SIX("6"),
  33.         SEVEN("7"), EIGHT("8"), NINE("9"), ZERO("0"), POINT(".");
  34.         private String operand;
  35.         private Operand(String operand) {
  36.             this.operand = operand;
  37.         }
  38.     }
  39.    
  40.     /**
  41.      * 获取字符串所对应的运算符枚举
  42.      * @param str
  43.      * @return
  44.      */
  45.     private Operator getOperator(String str) {
  46.         for (Operator op : Operator.values()) {
  47.             if (str.equals(op.operator)) {
  48.                 return op;
  49.             }
  50.         }
  51.         return null;
  52.     }
  53.     /**
  54.      * 获取字符串所对应的操作数枚举
  55.      * @param str
  56.      * @return
  57.      */
  58.     private Operand getOperand(String str) {
  59.         for (Operand op : Operand.values()) {
  60.             if (str.equals(op.operand)) {
  61.                 return op;
  62.             }
  63.         }
  64.         return null;
  65.     }   
  66.     /**
  67.      * 第1步: 将运算表达式字符串分解为运算表达式List
  68.      *
  69.      * @param exp
  70.      * @return
  71.      */
  72.     private List<String> resolveExpr(String exp) {
  73.         List<String> list = new LinkedList<String>();
  74.         String temp = "";
  75.         exp = exp.replace(" ", "");
  76.         for (int i = 0; i < exp.length(); i++) {
  77.             String str = exp.substring(i, i + 1);
  78.             Operator op = getOperator(str);
  79.             Operand od = getOperand(str);
  80.             if (op != null) {
  81.                 if (!temp.isEmpty()) {
  82.                     list.add(temp);
  83.                     temp = "";
  84.                 }
  85.                 list.add(str);
  86.             } else if (od != null) {
  87.                 temp += str;
  88.             } else {
  89.                 System.out.println("表达式[" + str + "]非法! ");
  90.                 return null;
  91.             }
  92.         }
  93.         if (!temp.isEmpty()) {
  94.             list.add(temp);
  95.         }
  96.         //System.out.println(list);
  97.         return list;
  98.     }
  99.     /**
  100.      * 第2步: 将运算表达式List转换为逆波兰表达式List
  101.      * @param expList
  102.      * @return
  103.      */
  104.     private List<String> dealExpr(List<String> expList) {
  105.         if(expList == null) {
  106.             return null;
  107.         }
  108.         
  109.         List<String> list = new LinkedList<String>();
  110.         Stack<String> stack = new Stack<String>();
  111.         for (String str : expList) {
  112.             Operator op = getOperator(str.substring(0, 1));
  113.             Operand od = getOperand(str.substring(0, 1));
  114.             if (od != null) {
  115.                 //操作数直接入队列
  116.                 list.add(str);
  117.             } else if (op != null) {
  118.                 if (Operator.PARENTHESIS_LEFT.equals(op)) {
  119.                     //左括号入栈
  120.                     stack.push(str);
  121.                 } else if (Operator.PARENTHESIS_RIGHT.equals(op)) {
  122.                     //右括号: 循环将栈顶的运算符取出并存入队列,直到取出左括号
  123.                     while (true) {
  124.                         if (stack.empty()) {
  125.                             System.out.println("缺少左括号! ");
  126.                             return null;
  127.                         } else if (Operator.PARENTHESIS_LEFT.operator.equals(stack.peek())) {
  128.                             stack.pop();
  129.                             break;
  130.                         } else {
  131.                             list.add(stack.pop());
  132.                         }
  133.                     }
  134.                 } else {
  135.                     //非括号类运算符
  136.                     if (!stack.empty()) {
  137.                         Operator top_op = getOperator(stack.peek());
  138.                         //当前运算符优先级大于栈顶运算符优先级,或者栈顶为左括号时,当前运算符直接入栈
  139.                         if(op.priority > top_op.priority
  140.                                 || Operator.PARENTHESIS_LEFT.equals(top_op)) {
  141.                             stack.push(str);
  142.                         }
  143.                         //否则,将栈顶的运算符取出并存入队列,然后将自己入栈
  144.                         else {
  145.                             list.add(stack.pop());
  146.                             stack.push(str);
  147.                         }                        
  148.                     } else {
  149.                         stack.push(str);
  150.                     }
  151.                 }
  152.             }
  153.         }
  154.         while(!stack.empty()) {
  155.             String str = stack.peek();
  156.             if(Operator.PARENTHESIS_LEFT.operator.equals(str)) {
  157.                 System.out.println("缺少右括号! ");
  158.                 return null;
  159.             } else {
  160.                 list.add(stack.pop());
  161.             }
  162.         }
  163.         //System.out.println(list);
  164.         return list;
  165.     }
  166.    
  167.     /**
  168.      * 操作数运算
  169.      * @param x
  170.      * @param y
  171.      * @param op
  172.      * @return
  173.      */
  174.     private String operation(String x, String y, Operator op) {
  175.         double a = 0.0;
  176.         double b = 0.0;
  177.         try {
  178.             a = Double.parseDouble(x);
  179.             b = Double.parseDouble(y);
  180.         } catch (NumberFormatException e) {
  181.             System.out.println("操作数非法! ");
  182.             e.printStackTrace();
  183.         }
  184.         
  185.         switch (op) {
  186.         case ADD:
  187.             return String.valueOf(a + b);
  188.         case SUBTRACT:
  189.             return String.valueOf(a - b);
  190.         case MULTIPLY:
  191.             return String.valueOf(a * b);
  192.         case DIVIDE:
  193.             return String.valueOf(a / b);
  194.         default:
  195.             return null;
  196.         }
  197.     }
  198.    
  199.     /**
  200.      * 第3步: 逆波兰表达式运算
  201.      * @param exp
  202.      * @return
  203.      */
  204.     public String calculate(String exp) {
  205.         List<String> expList = dealExpr(resolveExpr(exp));
  206.         if(expList == null) {
  207.             return null;
  208.         }
  209.         Stack<String> stack = new Stack<String>();
  210.         for(String str : expList) {
  211.             Operator op = getOperator(str.substring(0, 1));
  212.             Operand od = getOperand(str.substring(0, 1));
  213.             if(od != null) {
  214.                 stack.push(str);
  215.             } else if (op != null) {
  216.                 //目前仅针对二元运算符
  217.                 String x = "";
  218.                 String y = "";
  219.                 if(!stack.empty()) {
  220.                     y = stack.pop();
  221.                 }
  222.                 if(!stack.empty()) {
  223.                     x = stack.pop();
  224.                 }               
  225.                 if(!x.isEmpty() && !x.isEmpty()) {
  226.                     String result = operation(x, y, op);
  227.                     if(result == null) {
  228.                         return null;
  229.                     }
  230.                     stack.push(result);
  231.                 } else {
  232.                     return null;
  233.                 }
  234.             }
  235.         }
  236.         return stack.pop();
  237.     }   
  238. }
复制代码



测试一下:

  1. package ch8;
  2. /**
  3. * 测试
  4. * @author Jinjichao
  5. *
  6. */
  7. public class Test {
  8.     public static void main(String[] args) {
  9.         Calculator cal = new Calculator();
  10.         String str = cal.calculate("( ( ( 15 / 3 ) + ( 1.5 * 2 ) + ( 20 - 12 ))  - 3.2 +2.3 + 5 ) ");
  11.         System.out.println("运算结果:" + str);
  12.     }
  13. }
复制代码


运行结果:
运算结果:20.1
其他的测试案例:

<IGNORE_JS_OP>



<IGNORE_JS_OP>



<IGNORE_JS_OP>




算法原理(对照截图):
第1步、将表达式字符串分解为运算表达式List(将运算符和操作数分别分解出来)
第2步:将运算表达式List转换为逆波兰表达式List

第3步:逆波兰表达式运算

原文地址:https://www.cnblogs.com/firstdream/p/5649655.html