支持括號的仿android計算器
可以計算帶括號的表達式,不過前提是:正確的表達式才行
package com.fire.utils;import java.text.DecimalFormat; import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer;
/**
- 工具類
@author FireAnt / public class Tools {
public static int i = 0;
/**
- 計算一個合法的表達式的值
- @param exp
@return */ public static String cal(String exp) {
// 特殊表達式的處理方式 if (exp.length() == 0) {
return "";
} else if (exp.length() == 1) {
if (exp.equals(".")) { return "0"; } else { return ""; }
} else if (exp.matches(".÷0.")) { // 0作為除數
return "∞";
} else if (exp.matches(".*[+-/×÷]")) {
exp = exp.substring(0, exp.length() - 1); if (exp.equals(".")) { return "0"; }
}
// 如果表達式中有括號則遞歸計算 if (exp.contains("(")) {
// 找出最后一個左括號 int left = exp.lastIndexOf("("); // 找出第一個右括號 int right = exp.indexOf(")"); // 獲取第一個子表達式 String subExp = exp.substring(left + 1, right); // 計算子表達式的結果 String res = cal(subExp); // 用計算出來的結果替換子表達式 exp = exp.substring(0, left) + res + exp.substring(right + 1); // 遞歸計算新的表達式 exp = cal(exp);
}
// 格式化表達式 String newExp = formatExp(exp); List<Character> opts = getOptions(newExp); List<Double> nums = getNums(newExp);
// 先處理乘除 for (int i = 0; i < opts.size(); i++) {
char opt = opts.get(i); if (opt == '÷' || opt == '×') { opts.remove(i); double d1 = nums.remove(i); double d2 = nums.remove(i); if (opt == '÷') { d1 = d1 / d2; } else { d1 = d1 * d2; } nums.add(i, d1); i--; }
}
while (!opts.isEmpty()) {
char opt = opts.remove(0); double d1 = nums.remove(0); double d2 = nums.remove(0); if (opt == '+') { d1 = d1 + d2; } else { d1 = d1 - d2; } nums.add(0, d1);
}
return formatNum(nums.get(0)); }
/**
- 獲得一個表達式中所有的運算符
- @param exp
@return */ private static List<Character> getOptions(String exp) {
List<Character> opts = new ArrayList<Character>(); StringTokenizer st = new StringTokenizer(exp, "@.0123456789"); while (st.hasMoreTokens()) {
opts.add(st.nextToken().charAt(0));
} return opts; }
/**
- 獲得一個表達式中所有的數字
- @param exp
@return */ private static List<Double> getNums(String exp) {
List<Double> nums = new ArrayList<Double>(); StringTokenizer st = new StringTokenizer(exp, "+-×÷"); while (st.hasMoreTokens()) {
String num = st.nextToken(); if (num.contains("@")) { num = "-" + num.substring(1); } nums.add(Double.parseDouble(num));
} return nums; }
/**
- 格式一個浮點數
- @param num
@return */ public static String formatNum(double num) {
DecimalFormat df = (DecimalFormat) NumberFormat.getInstance();
df.applyLocalizedPattern("#0.##########"); if (num > 1000000000) {
df.applyPattern("#0.#######E0");
}
return df.format(num); }
/**
- 格式化表達式
- 1.替換操作(找出負號,并將其替換成@符號)
2.避免非法表達式的出現 */ private static String formatExp(String exp) {
// 如果表達式是以運算符結束的,則將最后一位運算符去除 if (exp.matches(".*[+-/×÷]")) {
exp = exp.substring(0, exp.length() - 1);
} String res = exp; if (exp.charAt(0) == '-') {
res = "@" + res.substring(1);
}
for (int i = 1; i < res.length(); i++) {
if (res.charAt(i) == '-' && (res.charAt(i - 1) == '÷' || res.charAt(i - 1) == '×')) { res = res.substring(0, i) + "@" + res.substring(i + 1); }
} return res; }
/**
- 檢查表達式是否有括號,并且檢查是否符合
- @param exp
@return */ public static boolean checkExp(String exp) {
boolean res = true;
int index = exp.indexOf("("); if (index != -1) {
int leftN = 0; for (int i = index; i < exp.length(); i++) { if (exp.charAt(i) == '(') { leftN++; } else if (exp.charAt(i) == ')') { leftN--; if (leftN == -1) { res = false; break; } } } if (leftN > 0) { res = false; }
}
return res; } }
</pre>