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步:逆波蘭表達式運算


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM