支持括号的仿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; } }