闲的没事写的一个计算器的核心逻辑
首先会判断算式的左括号 和 右括号是不是对等的。如果不对等则添加右括号
然后判断出来最小的括号,将里边的算式计算成数值,然后替换括号内的内容,
递归判断算式中是否有括号,如果没有了最后调用一下计算算式值的方法返回最终结果
package com.eleven.util;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Stack;
/**
* @author eleven
* @date 2021/11/2 13:35
* @apiNote
*/
public class CalculateUtil {
/** 数字栈 */
private static final Stack<BigDecimal> numberStack = new Stack<>();
/** 符号栈 */
private static final Stack<Character> symbolStack = new Stack<>();
/** 将百分号处理成小数 */
private static final BigDecimal HUNDRED = new BigDecimal(100);
/** 左括号 */
private static final String LEFT_BRACKET = "(";
/** 右括号 */
private static final String RIGHT_BRACKET = ")";
public static void main(String[] args) {
String validate = "7+8*9/4";
System.out.println(execute(validate));
}
/**
* 运行方法
* @param str 需要计算结果的式子
* @return String 返回运算的结果
*/
public static String execute(String str){
if(str.length() - str.replaceAll("[0-9]", "").length() == 0){
throw new RuntimeException("算式错误");
}
String afterComputedStr = str.contains(LEFT_BRACKET) ?
getLeastParentheses(matchingParentheses(str)) :
calculate(str);
StringBuilder sb = new StringBuilder(afterComputedStr);
StringBuilder reverseSb = new StringBuilder().append(Double.parseDouble(sb.reverse().toString()));
return reverseSb.reverse().toString();
}
/**
* 匹配括号的数量
* @param str 要校验的字符串
* @return 如果左括号和右括号的数量不一致的话添加右括号
*/
private static String matchingParentheses(String str){
str = str.replaceAll("()", "");
int length = str.length();
int left = length - str.replace("(","").length();
int right = length - str.replace(")","").length();
if(left != right){
for (int i = 0; i < left - right; i++) {
str += ")";
}
}
return str;
}
private static String getLeastParentheses(String str){
int lastIndex = str.lastIndexOf(LEFT_BRACKET);
int latestIndex = str.indexOf(RIGHT_BRACKET,lastIndex);
String subStr = str.substring(lastIndex + 1,latestIndex);
String afterStr = str.substring(0, lastIndex) + calculate(subStr) + str.substring(latestIndex + 1);
while(afterStr.contains(LEFT_BRACKET)){
afterStr = getLeastParentheses(afterStr);
}
return calculate(afterStr);
}
private static String calculate(String str){
StringBuilder sb = new StringBuilder();
for (int i = 0; i < str.length(); i++) {
char itemChar = str.charAt(i);
if(isNumber(itemChar)){
sb.append(itemChar);
}
if(isSymbol(itemChar)){
boolean minusFlag = itemChar == '-' && (i == 0 || isSymbol(str.charAt(i - 1)));
if(minusFlag){
sb.append("-");
}else{
BigDecimal number = BigDecimal.valueOf(Double.parseDouble(sb.toString()));
sb = new StringBuilder();
if(itemChar == '%'){
number = number.divide(HUNDRED);
numberStack.push(number);
}else{
if(isLower(itemChar)){
numberStack.push(computed(symbolStack.pop(), number));
symbolStack.push(itemChar);
}else{
numberStack.push(number);
symbolStack.push(itemChar);
}
}
}
}
}
String lastStr = sb.toString();
if(lastStr != null && lastStr.length() != 0){
numberStack.push(BigDecimal.valueOf(Double.parseDouble(sb.toString())));
}
return computed() + "";
}
private static BigDecimal computed(){
for (Iterator iterator = symbolStack.iterator();iterator.hasNext();){
char symbol = symbolStack.pop();
BigDecimal number = numberStack.pop();
BigDecimal computed = computed(symbol, number);
numberStack.push(computed);
}
return numberStack.pop();
}
/**
* 计算
* @param symbol 运算符
* @param number 数字
* @return
*/
private static BigDecimal computed(char symbol,BigDecimal number){
switch (symbol){
case '*' :
number = number.multiply(numberStack.pop()) ;
break;
case '/' :
if(number.equals(BigDecimal.ZERO)){
throw new RuntimeException("不能除以0");
}
number = numberStack.pop().divide(number,BigDecimal.ROUND_UP);
break;
case '-' :
number = numberStack.pop().subtract(number);
break;
case '+' :
number = number.add(numberStack.pop());
break;
case '.' :
number = number.divide(BigDecimal.TEN);
break;
default :
break;
}
return number;
}
/**
* 比较符号的优先级
* @param symbol 算式中的运算符
* @return
*/
private static boolean isLower(char symbol){
if(symbolStack.isEmpty()){
return false;
}
Map<Character, Integer> priorityMap = getPriorityMap();
return priorityMap.get(symbol) >= priorityMap.get(symbolStack.peek());
}
private static boolean noSymbol(String str){
return str.length() - str.replaceAll("[-+/*.%(^)]","").length() == 0;
}
private static Map<Character,Integer> getPriorityMap(){
Map<Character,Integer> map = new HashMap<>(5);
map.put('%', 0);
map.put('/', 1);
map.put('*', 1);
map.put('-', 2);
map.put('+', 2);
return map;
}
/**
* 是否是数字
* @param itemChar 字符
* @return
*/
public static boolean isNumber(char itemChar){
return itemChar == '.' || itemChar >= '0' && itemChar <= '9';
}
/**
* 是否是符号
* @param itemChar 符号
* @return
*/
public static boolean isSymbol(char itemChar){
return !isNumber(itemChar);
}
}