java计算器,输入公式和对应变量的值

  • 目标:最近想写个东西,本质就是一个计算器,我们可以输入公式(例如:a+b),然后把公式的值(a:10,b:20)也输入进去。最后得到结果。
  • 核心:这个想法核心部分就是给一个公式,然后计算其结果。这个在网上有很多。比如我就参考的这个大佬的。附链接
    • 其核心思想就是用两个栈,一次记录操作数,一个值。链接中的方案数已经在字符串中了。
    • 然后需要找到这个数。我想要的是数在一个map中,直接get出来就好了。
    • 此外,计算过程中需要对减号特殊处理,因为这个减号可能表示这个数是要取反的。代码中我直接在数栈和运算符栈中分别加入了-1和乘号实现的。

java核心代码

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Map;
import java.util.Stack;

/**
 * @author xcs
 */
public class ComputeResultUtil {
    private String expression;
    private Map<Character, BigDecimal> valueMap;

    public ComputeResultUtil(String expression, Map<Character, BigDecimal> valueMap) {
        this.expression = expression;
        this.valueMap = valueMap;
    }

    public BigDecimal compute() {
        Stack<BigDecimal> nums = new Stack<>();
        Stack<Character> ops = new Stack<>();
        //记录是否需要把 - 作为 负数存储
        boolean isOperatorPre = false;

        for (int i = 0; i < expression.length(); i++) {
            char c = expression.charAt(i);
            if (Character.isAlphabetic(c)) {
                isOperatorPre = false;
                nums.push(valueMap.get(c));
            } else if (c == '(') {
                isOperatorPre = true;
                ops.push(c);
            } else if (c == ')') {
                // 计算括号中的内容,直到遇到左括号
                while (ops.peek() != '(') {
                    isOperatorPre = false;
                    nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
                }
                // 有括号也出栈
                ops.pop();
            } else if (isOperator(c)) {
                if (c == '-' && (isOperatorPre || ops.empty())) {
                    nums.push(new BigDecimal("-1"));
                    ops.push('*');
                    isOperatorPre = false;
                } else {
                    while (!ops.empty() && needCalculatePre(c, ops.peek())) {
                        nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
                    }
                    isOperatorPre = true;
                    ops.push(c);
                }
            }
        }
        while (!ops.empty()) {
            nums.push(calculateByOps(ops.pop(), nums.pop(), nums.pop()));
        }
        return nums.pop();
    }

    private static boolean isOperator(char c) {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }

    private static boolean needCalculatePre(char op1, char op2) {
        if (op2 == '(' || op2 == ')') {
            return false;
        }
        return (op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-') || (op2 == '+' || op2 == '-') && (op1 == '+' || op1 == '-');
    }

    private static BigDecimal calculateByOps(char op, BigDecimal b, BigDecimal a) {
        switch (op) {
            case '+':
                return a.add(b);
            case '-':
                return a.subtract(b);
            case '*':
                return a.multiply(b).setScale(4, BigDecimal.ROUND_HALF_UP);
            case '/':
                if (b.compareTo(BigDecimal.ZERO) == 0) {
                    throw new UnsupportedOperationException("Cannot divide by zero");
                }
                return a.divide(b, 4, RoundingMode.HALF_UP);
            default:
                throw new UnsupportedOperationException("Unknown operator " + op);
        }
    }
}

使用方代码

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

/**
 * @author xcs
 */
public class ComputeResultMain {
    public static void main(String[] args) {
        System.out.print("输入公式(公式中的变量目前只支持单字符):");
        Scanner sc = new Scanner(System.in);
        String formula = sc.nextLine();
        System.out.println("输入公式中的变量值(例如:a:123,空行表示结束):");

        Map<Character, BigDecimal> valueMap = new HashMap<>();
        while (true) {
            String value = sc.nextLine();
            if (value.trim().isEmpty()) {
                break; // 空行作为结束标志
            }
            String[] split = value.split("[::]");
            valueMap.put(split[0].charAt(0), new BigDecimal(split[1]));
        }
        ComputeResultUtil computeResult = new ComputeResultUtil(formula, valueMap);
        System.out.println("计算结果为:" + computeResult.compute());
    }
}
  • 收获:
    • 首先就是这个计算的过程,上学的时候应该是学过的,但是基本都忘了,也是实在懒得写,就直接百度了,再次看下也算是学习了。
    • 其次我也是第一次知道string.split(“[::]”)的写法,其含义是中文冒号和英文冒号拆分字符串。这种写法由于中括号中两个冒号中间没有拆分,所以适用于单字符。如果是多字符的,可以这样写.split(“字符1|字符2…”),例如"1###2##3".split(“###|##”),拆分结果是1,2,3。需要注意的是,其实现步骤可以理解为依次进行了两次拆分,但是拆分结果放在一个数组中。可以看下面两个图,一个"1###2##3".split(“###|##”),一个是"1###2##3".split(“##|###”),后者出现了#2的数据,这是因为后者先使用##进行拆分。
      在这里插入图片描述
      在这里插入图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值