支持括号的仿android计算器

2018-07-20    来源:open-open

容器云强势上线!快速搭建集群,上万Linux镜像随意使用
可以计算带括号的表达式,不过前提是:正确的表达式才行
 
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;
    }
}
 

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点!
本站所提供的图片等素材,版权归原作者所有,如需使用,请与原作者联系。

上一篇:Java 正则表达式小例子

下一篇:iOS:压缩图片