這個計算器不僅能夠進行四則運算,還支持添加括號進行優先級計算,例如下面算式:
10+(2*16-20/5)+7*2=52
Java源代碼:
1 import java.awt.BorderLayout; 2 import java.awt.Container; 3 import java.awt.event.ActionEvent; 4 import java.awt.event.ActionListener; 5 import java.util.Stack; 6 7 import javax.swing.JButton; 8 import javax.swing.JFrame; 9 import javax.swing.JLabel; 10 import javax.swing.JPanel; 11 import javax.swing.JTextField; 12 13 /** 14 * 計算器 15 */ 16 public class Calculator { 17 18 /** 數字棧:用於存儲表達式中的各個數字 */ 19 private Stack<Long> numberStack = null; 20 /** 符號棧:用於存儲運算符和括號 */ 21 private Stack<Character> symbolStack = null; 22 23 /** 24 * 解析並計算四則運算表達式(含括號),返回計算結果 25 * 26 * @param numStr 27 * 算術表達式(含括號) 28 */ 29 public long caculate(String numStr) { 30 numStr = removeStrSpace(numStr); // 去除空格 31 // 如果算術表達式尾部沒有‘=’號,則在尾部添加‘=’,表示結束符 32 if (numStr.length() > 1 && !"=".equals(numStr.charAt(numStr.length() - 1) + "")) { 33 numStr += "="; 34 } 35 // 檢查表達式是否合法 36 if (!isStandard(numStr)) { 37 System.err.println("錯誤:算術表達式有誤!"); 38 return 0; 39 } 40 // 初始化棧 41 numberStack = new Stack<Long>(); 42 symbolStack = new Stack<Character>(); 43 // 用於緩存數字,因為數字可能是多位的 44 StringBuffer temp = new StringBuffer(); 45 // 從表達式的第一個字符開始處理 46 for (int i = 0; i < numStr.length(); i++) { 47 char ch = numStr.charAt(i); // 獲取一個字符 48 if (isNumber(ch)) { // 若當前字符是數字 49 temp.append(ch); // 加入到數字緩存中 50 } else { // 非數字的情況 51 String tempStr = temp.toString(); // 將數字緩存轉為字符串 52 if (!tempStr.isEmpty()) { 53 long num = Long.parseLong(tempStr); // 將數字字符串轉為長整型數 54 numberStack.push(num); // 將數字壓棧 55 temp = new StringBuffer(); // 重置數字緩存 56 } 57 // 判斷運算符的優先級,若當前優先級低於棧頂的優先級,則先把計算前面計算出來 58 while (!comparePri(ch) && !symbolStack.empty()) { 59 long b = numberStack.pop(); // 出棧,取出數字,后進先出 60 long a = numberStack.pop(); 61 // 取出運算符進行相應運算,並把結果壓棧進行下一次運算 62 switch ((char) symbolStack.pop()) { 63 case '+': 64 numberStack.push(a + b); 65 break; 66 case '-': 67 numberStack.push(a - b); 68 break; 69 case '*': 70 numberStack.push(a * b); 71 break; 72 case '/': 73 numberStack.push(a / b); 74 break; 75 default: 76 break; 77 } 78 } // while循環結束 79 if (ch != '=') { 80 symbolStack.push(new Character(ch)); // 符號入棧 81 if (ch == ')') { // 去括號 82 symbolStack.pop(); 83 symbolStack.pop(); 84 } 85 } 86 } 87 } // for循環結束 88 89 return numberStack.pop(); // 返回計算結果 90 } 91 92 /** 93 * 去除字符串中的所有空格 94 */ 95 private String removeStrSpace(String str) { 96 return str != null ? str.replaceAll(" ", "") : ""; 97 } 98 99 /** 100 * 檢查算術表達式的基本合法性,符合返回true,否則false 101 */ 102 private boolean isStandard(String numStr) { 103 if (numStr == null || numStr.isEmpty()) // 表達式不能為空 104 return false; 105 Stack<Character> stack = new Stack<Character>(); // 用來保存括號,檢查左右括號是否匹配 106 boolean b = false; // 用來標記'='符號是否存在多個 107 for (int i = 0; i < numStr.length(); i++) { 108 char n = numStr.charAt(i); 109 // 判斷字符是否合法 110 if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "") 111 || "+".equals(n + "") || "-".equals(n + "") 112 || "*".equals(n + "") || "/".equals(n + "") 113 || "=".equals(n + ""))) { 114 return false; 115 } 116 // 將左括號壓棧,用來給后面的右括號進行匹配 117 if ("(".equals(n + "")) { 118 stack.push(n); 119 } 120 if (")".equals(n + "")) { // 匹配括號 121 if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括號是否匹配 122 return false; 123 } 124 // 檢查是否有多個'='號 125 if ("=".equals(n + "")) { 126 if (b) 127 return false; 128 b = true; 129 } 130 } 131 // 可能會有缺少右括號的情況 132 if (!stack.isEmpty()) 133 return false; 134 // 檢查'='號是否不在末尾 135 if (!("=".equals(numStr.charAt(numStr.length() - 1) + ""))) 136 return false; 137 return true; 138 } 139 140 /** 141 * 判斷字符是否是0-9的數字 142 */ 143 private boolean isNumber(char num) { 144 if (num >= '0' && num <= '9') 145 return true; 146 return false; 147 } 148 149 /** 150 * 比較優先級:如果當前運算符比棧頂元素運算符優先級高則返回true,否則返回false 151 */ 152 private boolean comparePri(char symbol) { 153 if (symbolStack.empty()) { // 空棧返回ture 154 return true; 155 } 156 157 // 符號優先級說明(從高到低): 158 // 第1級: ( 159 // 第2級: * / 160 // 第3級: + - 161 // 第4級: ) 162 163 char top = (char) symbolStack.peek(); // 查看堆棧頂部的對象,注意不是出棧 164 if (top == '(') { 165 return true; 166 } 167 // 比較優先級 168 switch (symbol) { 169 case '(': // 優先級最高 170 return true; 171 case '*': { 172 if (top == '+' || top == '-') // 優先級比+和-高 173 return true; 174 else 175 return false; 176 } 177 case '/': { 178 if (top == '+' || top == '-') // 優先級比+和-高 179 return true; 180 else 181 return false; 182 } 183 case '+': 184 return false; 185 case '-': 186 return false; 187 case ')': // 優先級最低 188 return false; 189 case '=': // 結束符 190 return false; 191 default: 192 break; 193 } 194 return true; 195 } 196 197 // 測試 198 public static void main(String args[]) { 199 String num = "10 + (2*16-20/5) + 7*2 "; // 默認的算式 200 // 創建一個窗口 201 JFrame win = new JFrame("計算器"); 202 Container con = win.getContentPane(); 203 JPanel pa = new JPanel(); 204 pa.add(new JLabel("輸入算式:")); // 添加一個標簽 205 final JTextField formulaText = new JTextField(num, 20); // 算式輸入框 206 pa.add(formulaText); 207 pa.add(new JLabel("=")); 208 final JTextField resultText = new JTextField(8); // 結果文本框 209 pa.add(resultText); 210 con.add(pa); 211 212 JButton bn = new JButton("計算"); // 實例化按鈕對象 213 con.add(bn, BorderLayout.EAST); // 將按鈕添加到右邊 214 win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 設置關閉窗口退出程序 215 win.pack(); // 自動調整大小 216 win.setLocationRelativeTo(null); // 設置窗口居中於屏幕 217 win.setVisible(true); // 顯示窗口 218 219 // 添加按鈕點擊事件 220 bn.addActionListener(new ActionListener() { 221 @Override 222 public void actionPerformed(ActionEvent e) { // 每當按鈕點擊時調用該方法 223 /* 計算器操作 */ 224 Calculator cal = new Calculator(); 225 String numStr = formulaText.getText(); // 獲得算式文本框中的文字 226 long result = cal.caculate(numStr); // 計算算式的結果 227 numStr = cal.removeStrSpace(numStr); // 去空格 228 formulaText.setText(numStr); // 將去空格的算式放回算式文本框中 229 resultText.setText(result + ""); // 在結果文本框中顯示結果 230 } 231 }); 232 } 233 } 234
運行結果:

優化支持浮點數計算:
import java.math.BigDecimal;
import java.util.Stack;
/**
* 算式計算
*/
public class FormulaUtil {
private int scale; // 進行除法出現無線循環小數時保留的精度
/** 數字棧:用於存儲表達式中的各個數字 */
private Stack<BigDecimal> numberStack = null;
/** 符號棧:用於存儲運算符和括號 */
private Stack<Character> symbolStack = null;
public FormulaUtil(int scale) {
super();
this.scale = scale;
}
public FormulaUtil() {
this(32);
}
/**
* 解析並計算四則運算表達式(含括號優先級),返回計算結果
*
* @param numStr
* 算術表達式(含括號)
*/
public BigDecimal caculate(String numStr) {
numStr = removeStrSpace(numStr); // 去除空格
// 如果算術表達式尾部沒有‘=’號,則在尾部添加‘=’,表示結束符
if (numStr.length() > 1
&& !"=".equals(numStr.charAt(numStr.length() - 1) + "")) {
numStr += "=";
}
// 檢查表達式是否合法
if (!isStandard(numStr)) {
System.err.println("錯誤:算術表達式有誤!");
return null;
}
// 初始化棧
if (numberStack == null) {
numberStack = new Stack<BigDecimal>();
}
numberStack.clear();
if (symbolStack == null) {
symbolStack = new Stack<Character>();
}
symbolStack.clear();
// 用於緩存數字,因為數字可能是多位的
StringBuffer temp = new StringBuffer();
// 從表達式的第一個字符開始處理
for (int i = 0; i < numStr.length(); i++) {
char ch = numStr.charAt(i); // 獲取一個字符
if (isNumber(ch)) { // 若當前字符是數字
temp.append(ch); // 加入到數字緩存中
} else { // 非數字的情況
String tempStr = temp.toString(); // 將數字緩存轉為字符串
if (!tempStr.isEmpty()) {
// long num = Long.parseLong(tempStr); // 將數字字符串轉為長整型數
BigDecimal num = new BigDecimal(tempStr);
numberStack.push(num); // 將數字壓棧
temp = new StringBuffer(); // 重置數字緩存
}
// 判斷運算符的優先級,若當前優先級低於棧頂的優先級,則先把計算前面計算出來
while (!comparePri(ch) && !symbolStack.empty()) {
BigDecimal b = numberStack.pop(); // 出棧,取出數字,后進先出
BigDecimal a = numberStack.pop();
// 取出運算符進行相應運算,並把結果壓棧進行下一次運算
switch ((char) symbolStack.pop()) {
case '+':
numberStack.push(a.add(b));
break;
case '-':
numberStack.push(a.subtract(b));
break;
case '*':
numberStack.push(a.multiply(b));
break;
case '/':
try {
numberStack.push(a.divide(b));
} catch (java.lang.ArithmeticException e) {
// 進行除法出現無限循環小數時,就會拋異常,此處設置精度重新計算
numberStack.push(a.divide(b, this.scale,
BigDecimal.ROUND_HALF_EVEN));
}
break;
default:
break;
}
} // while循環結束
if (ch != '=') {
symbolStack.push(new Character(ch)); // 符號入棧
if (ch == ')') { // 去括號
symbolStack.pop();
symbolStack.pop();
}
}
}
} // for循環結束
return numberStack.pop(); // 返回計算結果
}
/**
* 去除字符串中的所有空格
*/
private String removeStrSpace(String str) {
return str != null ? str.replaceAll(" ", "") : "";
}
/**
* 檢查算術表達式的基本合法性,符合返回true,否則false
*/
private boolean isStandard(String numStr) {
if (numStr == null || numStr.isEmpty()) // 表達式不能為空
return false;
Stack<Character> stack = new Stack<Character>(); // 用來保存括號,檢查左右括號是否匹配
boolean b = false; // 用來標記'='符號是否存在多個
for (int i = 0; i < numStr.length(); i++) {
char n = numStr.charAt(i);
// 判斷字符是否合法
if (!(isNumber(n) || "(".equals(n + "") || ")".equals(n + "")
|| "+".equals(n + "") || "-".equals(n + "")
|| "*".equals(n + "") || "/".equals(n + "") || "=".equals(n
+ ""))) {
return false;
}
// 將左括號壓棧,用來給后面的右括號進行匹配
if ("(".equals(n + "")) {
stack.push(n);
}
if (")".equals(n + "")) { // 匹配括號
if (stack.isEmpty() || !"(".equals((char) stack.pop() + "")) // 括號是否匹配
return false;
}
// 檢查是否有多個'='號
if ("=".equals(n + "")) {
if (b)
return false;
b = true;
}
}
// 可能會有缺少右括號的情況
if (!stack.isEmpty())
return false;
// 檢查'='號是否不在末尾
if (!("=".equals(numStr.charAt(numStr.length() - 1) + "")))
return false;
return true;
}
/**
* 判斷字符是否是0-9的數字
*/
private boolean isNumber(char num) {
if ((num >= '0' && num <= '9') || num == '.')
return true;
return false;
}
/**
* 比較優先級:如果當前運算符比棧頂元素運算符優先級高則返回true,否則返回false
*/
private boolean comparePri(char symbol) {
if (symbolStack.empty()) { // 空棧返回ture
return true;
}
// 符號優先級說明(從高到低):
// 第1級: (
// 第2級: * /
// 第3級: + -
// 第4級: )
char top = (char) symbolStack.peek(); // 查看堆棧頂部的對象,注意不是出棧
if (top == '(') {
return true;
}
// 比較優先級
switch (symbol) {
case '(': // 優先級最高
return true;
case '*': {
if (top == '+' || top == '-') // 優先級比+和-高
return true;
else
return false;
}
case '/': {
if (top == '+' || top == '-') // 優先級比+和-高
return true;
else
return false;
}
case '+':
return false;
case '-':
return false;
case ')': // 優先級最低
return false;
case '=': // 結束符
return false;
default:
break;
}
return true;
}
// 測試
public static void main(String args[]) {
String numStr = "10.000000000000000009 + (2*16-20/4) + 7*2.5 "; // 默認的算式
BigDecimal result = new FormulaUtil().caculate(numStr); // 計算算式的結果
System.out.println(numStr + "=");
System.out.println(result);
}
}
