声明:原创作品,转载时请注明文章来自SAP师太技术博客:www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4289892.html
1 import java.util.ArrayList; 2 import java.util.List; 3 import java.util.Stack; 4 import java.util.regex.Matcher; 5 import java.util.regex.Pattern; 6 7 public class ParseCalcMode { 8 9 public static List parse(String calcMode) { 10 List elementsList = new ArrayList(); 11 Pattern p = Pattern.compile("(\\d+)|([-+*/])|([\\(\\)])"); 12 13 Matcher m = p.matcher(calcMode); 14 while (m.find()) { 15 elementsList.add(m.group(0)); 16 // System.out.println(m.groupCount()); 17 } 18 return elementsList; 19 } 20 21 /** 22 * 进行混合运算 23 * 24 * @param srcStack 25 * @return 26 */ 27 28 private static String calcMix(Stack srcStack) { 29 Stack destStack = new Stack(); 30 // 否则有一个完成的带括计算式,则执行计算操作 31 String data1; 32 String opr; 33 String data2; 34 // 35 String elem = (String) srcStack.pop(); 36 37 // 先执行乘除表式 38 while (!elem.equals("(")) { 39 if ("*".equals(elem) || "/".equals(elem)) { 40 41 data1 = (String) srcStack.pop(); 42 opr = elem; 43 data2 = (String) destStack.pop(); 44 45 Stack tmpStack = new Stack(); 46 // 如果是连续的乘除,则把连续乘除表达式存入一个临时栈中,待整个连续乘除表达时放完后计算临栈 47 while (!srcStack.isEmpty() 48 && (srcStack.peek().equals("*") || srcStack.peek().equals("/"))) { 49 // 第一次放时 50 if (tmpStack.isEmpty()) { 51 tmpStack.push(data2); 52 tmpStack.push(elem); 53 tmpStack.push(data1); 54 } else { 55 tmpStack.push(srcStack.pop()); 56 tmpStack.push(srcStack.pop()); 57 } 58 System.out.println("临时栈 tmpStack=" + tmpStack); 59 } 60 61 // 如果不是连续的乘除时 62 if (tmpStack.isEmpty()) { 63 64 switch (opr.charAt(0)) { 65 case ‘*‘: 66 destStack.push(String.valueOf(Integer.parseInt(data1) 67 * Integer.parseInt(data2))); 68 break; 69 70 case ‘/‘: 71 destStack.push(String.valueOf(Integer.parseInt(data1) 72 / Integer.parseInt(data2))); 73 break; 74 } 75 76 } else { 77 78 destStack.push(calcSameLevel(tmpStack)); 79 80 } 81 82 System.out.println("乘除计算后 destStack = " + destStack); 83 } else { 84 // 如果不是乘除时直接放入目标栈中 85 destStack.push(elem); 86 System.out.println("非乘除直接放入 destStack = " + destStack); 87 } 88 89 if (srcStack.isEmpty()) { 90 break; 91 } 92 elem = (String) srcStack.pop(); 93 } 94 95 // 如果没有加减时 96 if (destStack.size() == 1) { 97 return (String) destStack.pop(); 98 } else { 99 // 后执行加减表式 100 return calcSameLevel(destStack); 101 } 102 103 } 104 105 /** 106 * 同级运算 107 * 108 * @param destStack 109 * @return 110 */ 111 private static String calcSameLevel(Stack destStack) { 112 String tmpResult = null; 113 String data1; 114 String opr; 115 String data2; 116 117 while (!destStack.isEmpty()) { 118 if (tmpResult == null) { 119 data1 = (String) destStack.pop(); 120 121 opr = (String) destStack.pop(); 122 123 data2 = (String) destStack.pop(); 124 125 } else { 126 data1 = tmpResult; 127 opr = (String) destStack.pop(); 128 data2 = (String) destStack.pop(); 129 } 130 switch (opr.charAt(0)) { 131 case ‘+‘: 132 tmpResult = String.valueOf(Integer.parseInt(data1) 133 + Integer.parseInt(data2)); 134 break; 135 136 case ‘-‘: 137 tmpResult = String.valueOf(Integer.parseInt(data1) 138 - Integer.parseInt(data2)); 139 break; 140 case ‘*‘: 141 tmpResult = String.valueOf(Integer.parseInt(data1) 142 * Integer.parseInt(data2)); 143 break; 144 145 case ‘/‘: 146 tmpResult = String.valueOf(Integer.parseInt(data1) 147 / Integer.parseInt(data2)); 148 break; 149 } 150 } 151 System.out.println("同优先级运算结果=" + tmpResult); 152 return tmpResult; 153 } 154 155 public static void main(String[] args) { 156 String str = "2*2+(10-2)/(101-50*2)*3-2+5"; 157 // String str ="2*(3+2-1)"; 158 List elementsList = parse(str); 159 System.out.println("组成算术表达式的各元素为=" + elementsList); 160 161 // 存入整体算术表达式各元素,在放入过程中如果遇到括号则要先计算括号里的算术式后再把计算出的结果放入栈中 162 Stack srcStack = new Stack(); 163 for (int i = 0; i < elementsList.size(); i++) { 164 String elem = (String) elementsList.get(i); 165 if (elem.equals(")")) { 166 System.out.println("遇到右括号,准备计算括号里的算术式,srcStack = " + srcStack); 167 srcStack.push(calcMix(srcStack)); 168 System.out.println("括号里的算术式计算完毕,srcStack = " + srcStack); 169 } else { 170 // 如果不为右括号放入栈 171 srcStack.push(elem); 172 System.out.println("非右括号,直接入栈 srcStack = " + srcStack); 173 } 174 } 175 System.out.println(srcStack); 176 // 所有括号里表达式计算完后计算整体算术式 177 if (srcStack.size() > 1) { 178 System.out.println("结果为=" + calcMix(srcStack)); 179 } else { 180 System.out.println("结果为=" + srcStack.pop()); 181 } 182 } 183 }
组成算术表达式的各元素为=[2, *, 2, +, (, 10, -, 2, ), /, (, 101, -, 50, *, 2, ), *, 3, -, 2, +, 5]
非右括号,直接入栈 srcStack = [2]
非右括号,直接入栈 srcStack = [2, *]
非右括号,直接入栈 srcStack = [2, *, 2]
非右括号,直接入栈 srcStack = [2, *, 2, +]
非右括号,直接入栈 srcStack = [2, *, 2, +, (]
非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10]
非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10, -]
非右括号,直接入栈 srcStack = [2, *, 2, +, (, 10, -, 2]
遇到右括号,准备计算括号里的算术式,srcStack = [2, *, 2, +, (, 10, -, 2]
非乘除直接放入 destStack = [2]
非乘除直接放入 destStack = [2, -]
非乘除直接放入 destStack = [2, -, 10]
同优先级运算结果=8
括号里的算术式计算完毕,srcStack = [2, *, 2, +, 8]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *, 2]
遇到右括号,准备计算括号里的算术式,srcStack = [2, *, 2, +, 8, /, (, 101, -, 50, *, 2]
非乘除直接放入 destStack = [2]
乘除计算后 destStack = [100]
非乘除直接放入 destStack = [100, -]
非乘除直接放入 destStack = [100, -, 101]
同优先级运算结果=1
括号里的算术式计算完毕,srcStack = [2, *, 2, +, 8, /, 1]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2, +]
非右括号,直接入栈 srcStack = [2, *, 2, +, 8, /, 1, *, 3, -, 2, +, 5]
[2, *, 2, +, 8, /, 1, *, 3, -, 2, +, 5]
非乘除直接放入 destStack = [5]
非乘除直接放入 destStack = [5, +]
非乘除直接放入 destStack = [5, +, 2]
非乘除直接放入 destStack = [5, +, 2, -]
非乘除直接放入 destStack = [5, +, 2, -, 3]
临时栈 tmpStack=[3, *, 1]
临时栈 tmpStack=[3, *, 1, /, 8]
同优先级运算结果=24
乘除计算后 destStack = [5, +, 2, -, 24]
非乘除直接放入 destStack = [5, +, 2, -, 24, +]
非乘除直接放入 destStack = [5, +, 2, -, 24, +, 2]
乘除计算后 destStack = [5, +, 2, -, 24, +, 4]
同优先级运算结果=31
结果为=31
上面实现的有点复杂了,下面想了下使用 LinkedList 可能要简单一些
使用LinkedList实现
1 import java.util.LinkedList; 2 import java.util.regex.Matcher; 3 import java.util.regex.Pattern; 4 5 /** 6 * 使用 LinkedList 计算算术表达试的值 7 * @author jzj 8 * 9 */ 10 public class ArithmeticCalc { 11 /** 12 * 提取算术表达式中的括号部分 13 * 14 * @param expression 算术表达式 15 * @return 16 */ 17 public static String bracket(String expression) { 18 Pattern p = Pattern.compile("\\(([^\\(]+?)\\)"); 19 20 Matcher m = p.matcher(expression); 21 22 if (m.find()) { 23 return m.group(1); 24 } 25 else { 26 return null; 27 } 28 } 29 30 /** 31 * 分解算术表达式 32 * 33 * @param expression 算术表达式 34 * @return 35 */ 36 public static LinkedList parse(String expression) { 37 LinkedList elemList = new LinkedList(); 38 //注,减号要放在第一个,放在中间时代表特殊意义 39 Pattern p = Pattern.compile("(\\d+)|[-+*/()]"); 40 41 Matcher m = p.matcher(expression); 42 while (m.find()) { 43 elemList.add(m.group(0)); 44 } 45 return elemList; 46 } 47 48 /** 49 * 计算不带括号的算术表达式 50 * @param expression 不带括号的算术表达式 51 * @return String 返回计算结果 52 */ 53 private static String caclExpression(String expression) { 54 //分解算术表达式 55 LinkedList linkList = parse(expression); 56 57 //先计算乘除 58 for (int i = 0; i < linkList.size(); i++) { 59 String e = (String) linkList.get(i); 60 if ("*".equals(e) || "/".equals(e)) { 61 String oprData1 = (String) linkList.remove(i - 1); 62 63 String opr = (String) linkList.remove(i - 1); 64 65 String oprData2 = (String) linkList.remove(i - 1); 66 67 //计算完成后将结果插入到原表达式所在位置 68 linkList.add(i - 1, cacl(oprData1, opr, oprData2)); 69 70 i = i - 1 - 1;//从结果位置向后计算 71 } 72 } 73 74 //再算计算加减 75 for (int i = 0; i < linkList.size() && linkList.size() > 1; i++) { 76 String oprData1 = (String) linkList.remove(i); 77 String opr = (String) linkList.remove(i); 78 String oprData2 = (String) linkList.remove(i); 79 //计算完成后将结果插入到原表达式所在位置 80 81 linkList.add(i, cacl(oprData1, opr, oprData2)); 82 i = i - 1;//从结果位置向后计算 83 } 84 85 return (String) linkList.get(0); 86 } 87 88 /** 89 * 两个数计算 90 * @param oprData1 操作数一 91 * @param opr 操作 92 * @param oprData2 操作数二 93 * @return String 返回计算结果 94 */ 95 private static String cacl(String oprData1, String opr, String oprData2) { 96 switch (opr.charAt(0)) { 97 case ‘+‘: 98 return String.valueOf(Integer.parseInt(oprData1) 99 + Integer.parseInt(oprData2)); 100 101 case ‘-‘: 102 return String.valueOf(Integer.parseInt(oprData1) 103 - Integer.parseInt(oprData2)); 104 case ‘*‘: 105 return String.valueOf(Integer.parseInt(oprData1) 106 * Integer.parseInt(oprData2)); 107 108 case ‘/‘: 109 return String.valueOf(Integer.parseInt(oprData1) 110 / Integer.parseInt(oprData2)); 111 default: 112 return ""; 113 } 114 } 115 116 public static void main(String[] args) { 117 String expression = "2*2+(2+5/(10-2*(1+1)*2-1))/(7-3*2)*3-2+5"; 118 String bracketStr; 119 //如果算术表达式中有括号,则先计算括号中的表达式 120 while ((bracketStr = bracket(expression)) != null) { 121 String result = caclExpression(bracketStr); 122 System.out.println(bracketStr + "=" + result); 123 bracketStr = bracketStr.replaceAll("\\*", "\\\\*").replaceAll( 124 "\\+", "\\\\+"); 125 expression = expression.replaceAll("\\(" + bracketStr + "\\)", 126 result); 127 } 128 129 System.out.println(expression + "=" + caclExpression(expression)); 130 } 131 }