java 计算器后台实现

有两种方案,第一种想到了就很简单,调用js脚本

public class CalculatorByJavaScript {
    public static void main(String[] args)  {
        String str = "15*7-(19-18*(11+12))";
        //执行JS脚本
        ScriptEngine jse = new ScriptEngineManager().getEngineByName("JavaScript");
        Object eval;
        try {
            eval = jse.eval(str);
            System.out.println(eval);
            if("Infinity".equals(eval.toString())) {
                throw new RuntimeException("分母不能为0");
            }
        } catch (Exception e) {
            if(e instanceof javax.script.ScriptException) {
                System.out.println(String.format("%s:表达式错误  %n %s" ,str,e.getMessage()));
            }else {
                System.out.println(e.getMessage());
            }
            e.printStackTrace();
        }
    }
}

  第二种就是用栈来实现,难点在于表达式中负数的截取:比如3+(-11),(-11)+3 

      还有就是对 后缀表达式,中缀表达式的理解(不明白的,百度一下)

    

package com.zh.javaweb.calculator;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;
import java.util.Stack;

import org.springframework.util.NumberUtils;

/**
 * @author zhouhong
 * @createDate 2019年1月17日 下午12:10:58
 */
public class CalculatorByJava {

    @SuppressWarnings("resource")
    public static void main(String[] args) {

        Scanner scan = new Scanner(System.in);
        while (true) {
            String mid = scan.nextLine();
            if (mid.equals("")) {
                System.out.println("已结束输入!");
                break;
            }
            List<String> list = transferToBehind(mid);

            BigDecimal comeOut = calculator(list);
            System.out.println(comeOut);

        }
    }

    /**
     * 将表达式分割,eg:2+66*2  1,+,*,2
     * @author: zhouhong 
     * @date: 2019年1月17日 下午12:24:30 
     * @param mid
     * @return
     */
    private static List<String> transferToBehind(String mid) {
        //去除前后空格
        char[] charArray = mid.trim().toCharArray();
        //解析字符数组
        String str = transferToStr(charArray);

        return transferToList(str);
    }

    /**
     * 把带有1,2+3,,0,-1 字符串转换成 list 去掉中间的空格
     * @author: zhouhong 
     * @date: 2019年1月17日 下午2:23:29 
     * @param str
     * @return
     */
    private static List<String> transferToList(String str) {

        String[] split = str.split(",");
        List<String> asList = new ArrayList<>(Arrays.asList(split));
        Iterator<String> iterator = asList.iterator();
        while (iterator.hasNext()) {
            String next = iterator.next();
            if (next == null || " ".equals(next) || "".equals(next)) {
                iterator.remove();
            }
        }
        return asList;

    }

    /**
     * 
     * @author: zhouhong 
     * @date: 2019年1月17日 下午2:17:34 
     * @param charArray
     * @return
     */
    private static String transferToStr(char[] charArray) {

        String str = "";
        for (int i = 0; i < charArray.length; i++) {
            char c = charArray[i];
            if (i == 0 && checkNumber(c)) {//判断首位是数字
                str = str  + c;
                continue;
            }
            if (i == 0 && "-".equals(String.valueOf(c))) {//判断首位是负数-
                str = str + "," + c;
                continue;
            }
            if ("(".equals(String.valueOf(c)) || ")".equals(String.valueOf(c))) {//判断是否是括号
                str = str + "," + c + ",";
                continue;
            }
            if ("(".equals(String.valueOf(charArray[i - 1])) && checkSymbol(c)) {//判断左括号后面是符号比如(-1) (-
                str = str + "," + c+charArray[i=i + 1];
                continue;
            }
            if ("(".equals(String.valueOf(charArray[i - 1])) && checkNumber(c)) {//判断左括号后面是否是数字比如(1) (1
                if(checkNumber(charArray[i +1])) {
                    str = str + "," + c + charArray[i=i + 1];
                }else {
                    str = str + "," + c + ",";
                }
                
                continue;
            }

            if (checkSymbol(c)) {
                str = str + "," + c + ",";
            }
            if (checkNumber(c)) {
                str += c;
            }

        }
        return str;

    }

    private static BigDecimal calculator(List<String> list) {

        Stack<String> s1 = new Stack<String>();//用于计算 --后缀表达式
        Stack<String> s2 = new Stack<String>();//出栈
        pushStack(list, s1);
        popStack(s1,s2);
        return new BigDecimal(s2.pop());

    }

    private static void popStack(Stack<String> s1, Stack<String> s2) {
       //[9, 3, 1, -, 3, *, +, 10, 2, /, +]
        Stack<String> temp = new Stack<String>();
        while(!s1.empty()) {
            temp.push(s1.pop());
        }
        
        while(!temp.empty()) {
            if (checkNumber(temp.peek())) { //检查数字
                s2.push(temp.pop());
                continue;
            }
            BigDecimal num1  = new BigDecimal(s2.pop());
            BigDecimal num2  = new BigDecimal(s2.pop());
            
            switch (temp.pop()) {
                case "+":
                    BigDecimal add = num2.add(num1);
                    s2.push(String.valueOf(add.intValue()));
                    break;
                case "-":
                    BigDecimal subtract = num2.subtract(num1);
                    s2.push(String.valueOf(subtract.intValue()));
                    break;
                case "*":
                    BigDecimal multiply = num2.multiply(num1);
                    s2.push(String.valueOf(multiply.intValue()));
                    break;
                case "/":
                    BigDecimal divide = num2.divide(num1);
                    s2.push(String.valueOf(divide.intValue()));
                    break;

                default:
                    break;
            }
        }
    }

    private static void pushStack(List<String> list, Stack<String> s1) {
        Stack<SymbolEnum> s2 = new Stack<SymbolEnum>();//临时存放运算符 -- 中缀
        for (String str : list) {
            pushStack(str,s1,s2);
        }
        while(!s2.isEmpty()) {
            s1.push(s2.pop().getType());
        }
    }

    private static void pushStack(String str, Stack<String> s1, Stack<SymbolEnum> s2) {

        if (checkNumber(str)) { //检查数字
            s1.push(str);
            return;
        }
        if ("(".equals(str)) {//检查左括号
            s2.push(SymbolEnum.getValue(str));
            return;
        }
        if (checkSymbol(str.toCharArray()[0])) { //检查运算符
            SymbolEnum symbol1 = SymbolEnum.getValue(str);
            if (s2.empty()) {
                s2.push(symbol1);
            }else {
                SymbolEnum symbol2 = s2.peek();
                if(symbol2.getNum() < 4 ) {
                    while(!s2.empty() && symbol1.getNum() <=s2.peek().getNum() ) {
                        s1.push(s2.pop().getType());
                    }
                }
               s2.push(symbol1);  
            }
        }
        if (")".equals(str)) {//检查右括号
            while(!s2.peek().getType().equals("(") ) {
                s1.push(s2.pop().getType());
            }
            s2.pop();//删除左括号
        }
    }

    /**
     * 判断是否是运算符 + - * /
     * @author: zhouhong 
     * @date: 2019年1月17日 上午1:34:06 
     * @param word
     * @return
     */
    public static boolean checkSymbol(char word) {
        if (word == '+' || word == '-' || word == '*' || word == '/') {
            return true;
        }
        return false;
    }

    /**
     * 判断数字
     * @author: zhouhong 
     * @date: 2019年1月17日 上午1:35:58 
     * @param word
     * @return
     */
    public static boolean checkNumber(char word) {
        if ((word >= '0' && word <= '9') || word == '.') {
            return true;
        }
        return false;
    }

    public static boolean checkNumber(String word) {
        try {
            NumberUtils.parseNumber(word, BigDecimal.class);
            return true;
        }catch(Exception e) {
            
            return false;
        }
    }

}

enum SymbolEnum {
     RIGHT_BRACKETS(")", 8), 
     LEFT_BRACKETS("(",4), 
     MULTIPLY("*",2), 
     EXCEPT("/", 2), 
     ADD("+",1), 
     REDUCE("-",1),;

    String type;
    int    num;

    public static  SymbolEnum getValue(String type) {
        for (SymbolEnum symbol : SymbolEnum.values()) {
             if(symbol.getType().equals(type)) {
                 return symbol;
             }
        }
        return null;
    }
    
    public static  SymbolEnum getValue(int num) {
        for (SymbolEnum symbol : SymbolEnum.values()) {
            if(symbol.getNum() == num) {
                return symbol;
            }
        }
        return null;
    }
    
    
    
    
    private SymbolEnum(String type, int num) {
        this.type = type;
        this.num = num;
    }

    public String getType() {
        
        return type;
    }


    public int getNum() {

        return num;
    }


}