Java计算数学表达式

55次阅读

共计 9927 个字符,预计需要花费 25 分钟才能阅读完成。

Java 计算数学表达式。CalculatorUtil.conversion((10+2)/-(20/5)+10);

public class CalculatorUtil {private Stack<String> postfixStack = new Stack<String>();// 后缀式栈
    private Stack<Character> opStack = new Stack<Character>();// 运算符栈
    private int[] operatPriority = new int[] {0, 3, 2, 1, -1, 1, 0, 2};// 运用运算符 ASCII 码 -40 做索引的运算符优先级

    public static double conversion(String expression) {
        double result = 0;
        CalculatorUtil cal = new CalculatorUtil();
        try {expression = transform(expression);
            result = cal.calculate(expression);
        } catch (Exception e) {return 0.0;}
        return result;
    }

    /**
     * 将表达式中负数的符号更改
     *
     * @param expression
     *            例如 -2+-1*(-3E-2)-(-1) 被转为 ~2+~1*(~3E~2)-(~1)
     * @return
     */
    private static String transform(String expression) {char[] arr = expression.toCharArray();
        for (int i = 0; i < arr.length; i++) {if (arr[i] == '-') {if (i == 0) {arr[i] = '~';
                } else {char c = arr[i - 1];
                    if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == 'E' || c == 'e') {arr[i] = '~';
                    }
                }
            }
        }
        if(arr[0]=='~'||arr[1]=='('){arr[0]='-';
            return "0"+new String(arr);
        }else{return new String(arr);
        }
    }

    /**
     * 按照给定的表达式计算
     *
     * @param expression
     *            要计算的表达式例如:5+12*(3+5)/7
     * @return
     */
    public double calculate(String expression) {Stack<String> resultStack = new Stack<String>();
        prepare(expression);
        Collections.reverse(postfixStack);// 将后缀式栈反转
        String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
        while (!postfixStack.isEmpty()) {currentValue = postfixStack.pop();
            if (!isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
                currentValue = currentValue.replace("~", "-");
                resultStack.push(currentValue);
            } else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
                secondValue = resultStack.pop();
                firstValue = resultStack.pop();

                // 将负数标记符改为负号
                firstValue = firstValue.replace("~", "-");
                secondValue = secondValue.replace("~", "-");

                String tempResult = calculate(firstValue, secondValue, currentValue.charAt(0));
                resultStack.push(tempResult);
            }
        }
            return Double.valueOf(resultStack.pop());
    }

    /**
     * 数据准备阶段将表达式转换成为后缀式栈
     * 
     * @param expression
     */
    private void prepare(String expression) {opStack.push(',');// 运算符放入栈底元素逗号,此符号优先级最低
        char[] arr = expression.toCharArray();
        int currentIndex = 0;// 当前字符的位置
        int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
        char currentOp, peekOp;// 当前操作符和栈顶操作符
        for (int i = 0; i < arr.length; i++) {currentOp = arr[i];
            if (isOperator(currentOp)) {// 如果当前字符是运算符
                if (count > 0) {postfixStack.push(new String(arr, currentIndex, count));// 取两个运算符之间的数字
                }
                peekOp = opStack.peek();
                if (currentOp == ')') {// 遇到反括号则将运算符栈中的元素移除到后缀式栈中直到遇到左括号
                    while (opStack.peek() != '(') {postfixStack.push(String.valueOf(opStack.pop()));
                    }
                    opStack.pop();} else {while (currentOp != '(' && peekOp != ',' && compare(currentOp, peekOp)) {postfixStack.push(String.valueOf(opStack.pop()));
                        peekOp = opStack.peek();}
                    opStack.push(currentOp);
                }
                count = 0;
                currentIndex = i + 1;
            } else {count++;}
        }
        if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符的则加入后缀式栈中
            postfixStack.push(new String(arr, currentIndex, count));
        }

        while (opStack.peek() != ',') {postfixStack.push(String.valueOf(opStack.pop()));// 将操作符栈中的剩余的元素添加到后缀式栈中
        }
    }

    /**
     * 判断是否为算术符号
     *
     * @param c
     * @return
     */
    private static boolean isOperator(char c) {return c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')';
    }

    /**
     * 利用 ASCII 码 -40 做下标去算术符号优先级
     *
     * @param cur
     * @param peek
     * @return
     */
    public boolean compare(char cur, char peek) {// 如果是 peek 优先级高于 cur,返回 true,默认都是 peek 优先级要低
        boolean result = false;
        if (operatPriority[(peek) - 40] >= operatPriority[(cur) - 40]) {result = true;}
        return result;
    }

    /**
     * 按照给定的算术运算符做计算
     *
     * @param firstValue
     * @param secondValue
     * @param currentOp
     * @return
     */
    private String calculate(String firstValue, String secondValue, char currentOp) {
        String result = "";
        switch (currentOp) {
        case '+':
            result = String.valueOf(ArithHelper.add(firstValue, secondValue));
            break;
        case '-':
            result = String.valueOf(ArithHelper.sub(firstValue, secondValue));
            break;
        case '*':
            result = String.valueOf(ArithHelper.mul(firstValue, secondValue));
            break;
        case '/':
            result = String.valueOf(ArithHelper.div(firstValue, secondValue));
            break;
        }
        return result;
    }
    
    public static List<String> getQueryField(String exp) {List<String> list = new ArrayList<String>();
        if (exp!=null && !"".equals(exp)) {exp = exp.replaceAll("[()]", "");
            exp = exp.replaceAll("[\\+\\-\\*\\/]", ",");
            list = new ArrayList<String>(Arrays.asList(exp.split(",")));
        }
        return list;
    }
    
    public static String getQueryField2(String exp) {if (exp!=null && !"".equals(exp)) {exp = exp.replaceAll("[()]", "");
            exp = exp.replaceAll("[\\+\\-\\*\\/]", "");
        }
        return exp;
    }
    
    /**
     * 获取除法后面的表达式 数据库分母为空处理
     * @param expression
     * @return
     */
    public static List<String> expExcuteChain(String expression){List<String> list = new ArrayList<String>();
        new CalculatorUtil().calculateChain(expression, list);
        return list;
    } 

    private void calculateChain(String expression, List<String> list) {Stack<String> resultStack = new Stack<String>();
        prepare(expression);
        Collections.reverse(postfixStack);// 将后缀式栈反转
        String firstValue, secondValue, currentValue;// 参与计算的第一个值,第二个值和算术运算符
        while (!postfixStack.isEmpty()) {currentValue = postfixStack.pop();
            if (!isOperator(currentValue.charAt(0))) {// 如果不是运算符则存入操作数栈中
                resultStack.push(currentValue);
            } else {// 如果是运算符则从操作数栈中取两个值和该数值一起参与运算
                secondValue = resultStack.pop();
                firstValue = resultStack.pop();
                String oprType = String.valueOf(currentValue.charAt(0));
                String tempResult = firstValue.concat(oprType).concat(secondValue);
                resultStack.push(tempResult);
                if ("/".equals(oprType)) {list.add(tempResult.substring(firstValue.length()+1, tempResult.length()));    
                }
            }
        }
    }

    /**
     * 替换表达式中的值 a 替换成 sum(a)
     * @param expression
     * @return
     */
    public static String getFieldByStr(String expression, String addStr) {if ("avg".equals(addStr)) {addStr = "sum";}
        StringBuffer fBuffer = new StringBuffer();
        char[] arr = expression.toCharArray();
        int currentIndex = 0;// 当前字符的位置
        int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
        char currentOp;// 当前操作符和栈顶操作符
        String oriField = "";
        for (int i = 0; i < arr.length; i++) {currentOp = arr[i];
            if (isOperator(currentOp)) {// 如果当前字符是运算符
                if (count > 0) {oriField = new String(arr, currentIndex, count);
                    if (!"".equals(addStr)) {oriField = addStr.concat("(").concat(oriField).concat(")");
                    }
                    fBuffer.append(oriField);// 取两个运算符之间的内容
                }
                fBuffer.append(String.valueOf(currentOp));
                count = 0;
                currentIndex = i + 1;
            } else {count++;}
        }
        if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符
            oriField = new String(arr, currentIndex, count);
            if (!"".equals(addStr)) {oriField = addStr.concat("(").concat(oriField).concat(")");
            }
            fBuffer.append(oriField);
        }
        return fBuffer.toString();}
    
    /**
     * 替换表达式中的值 a 替换成 1
     * @param expression
     * @return
     */
    public static String getFieldByStr(String expression, Map<String, Object> valueMap) {StringBuffer fBuffer = new StringBuffer();
        char[] arr = expression.toCharArray();
        int currentIndex = 0;// 当前字符的位置
        int count = 0;// 上次算术运算符到本次算术运算符的字符的长度便于或者之间的数值
        char currentOp;// 当前操作符和栈顶操作符
        String oriField = "";
        for (int i = 0; i < arr.length; i++) {currentOp = arr[i];
            if (isOperator(currentOp)) {// 如果当前字符是运算符
                if (count > 0) {oriField = new String(arr, currentIndex, count);
                    oriField = getMapKeyVal(valueMap, oriField);
                    fBuffer.append(oriField);// 取两个运算符之间的内容
                }
                fBuffer.append(String.valueOf(currentOp));
                count = 0;
                currentIndex = i + 1;
            } else {count++;}
        }
        if (count > 1 || (count == 1 && !isOperator(arr[currentIndex]))) {// 最后一个字符不是括号或者其他运算符
            oriField = new String(arr, currentIndex, count);
            oriField = getMapKeyVal(valueMap, oriField);
            fBuffer.append(oriField);
        }
        return fBuffer.toString();}
    
    public static <K, V> String getMapKeyVal(Map<K, V> queryMap, String key){return  (queryMap == null || queryMap.isEmpty()) ? "": (queryMap.containsKey(key) ? (queryMap.get(key) == null ?"" : queryMap.get(key).toString()) : "");
    }
}
class ArithHelper {
    // 默认除法运算精度
    private static final int DEF_DIV_SCALE = 10;

    // 这个类不能实例化
    private ArithHelper() {}

    /**
     * 提供精确的加法运算。*
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */

    public static double add(double v1, double v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
        java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();}

    public static double add(String v1, String v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.add(b2).doubleValue();}

    /**
     * 提供精确的减法运算。*
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */

    public static double sub(double v1, double v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
        java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();}

    public static double sub(String v1, String v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.subtract(b2).doubleValue();}

    /**
     * 提供精确的乘法运算。*
     * @param v1
     *            被乘数
     * @param v2
     *            乘数
     * @return 两个参数的积
     */

    public static double mul(double v1, double v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
        java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();}

    public static double mul(String v1, String v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.multiply(b2).doubleValue();}

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后 10 位,以后的数字四舍五入。*
     * @param v1
     *            被除数
     * @param v2
     *            除数
     * @return 两个参数的商
     */

    public static double div(double v1, double v2) {return div(v1, v2, DEF_DIV_SCALE);
    }

    public static double div(String v1, String v2) {java.math.BigDecimal b1 = new java.math.BigDecimal(v1);
        java.math.BigDecimal b2 = new java.math.BigDecimal(v2);
        return b1.divide(b2, DEF_DIV_SCALE, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();}

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由 scale 参数指 定精度,以后的数字四舍五入。*
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示表示需要精确到小数点以后几位。* @return 两个参数的商
     */

    public static double div(double v1, double v2, int scale) {if (scale < 0) {throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        java.math.BigDecimal b1 = new java.math.BigDecimal(Double.toString(v1));
        java.math.BigDecimal b2 = new java.math.BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();}

    /**
     * 提供精确的小数位四舍五入处理。*
     * @param v 需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */

    public static double round(double v, int scale) {if (scale < 0) {throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        java.math.BigDecimal b = new java.math.BigDecimal(Double.toString(v));
        java.math.BigDecimal one = new java.math.BigDecimal("1");
        return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();}

    public static double round(String v, int scale) {if (scale < 0) {throw new IllegalArgumentException("The   scale   must   be   a   positive   integer   or   zero");
        }
        java.math.BigDecimal b = new java.math.BigDecimal(v);
        java.math.BigDecimal one = new java.math.BigDecimal("1");
        return b.divide(one, scale, java.math.BigDecimal.ROUND_HALF_UP).doubleValue();}
}

正文完
 0