import java.math.BigDecimal;
import java.util.*;
/**
* 简单的公式计算工具,仅支持+ 、-、*、/、()
* @author ningyongli
* @date 2020-07-13
*/
public class CalculateUtils {
private static final Map<String, Integer> PRIORITY_MAP = new HashMap<>();
private static final List<String> OPERATOR_LIST = new ArrayList<>();
static {
PRIORITY_MAP.put("(", 0);
PRIORITY_MAP.put("+", 5);
PRIORITY_MAP.put("-", 5);
PRIORITY_MAP.put("*", 10);
PRIORITY_MAP.put("/", 10);
PRIORITY_MAP.put(")", 15);
OPERATOR_LIST.add("+");
OPERATOR_LIST.add("-");
OPERATOR_LIST.add("*");
OPERATOR_LIST.add("/");
OPERATOR_LIST.add("(");
OPERATOR_LIST.add(")");
}
/**
* 计算入口,除法计算小数位为16位
* @param data 数据
* @param express 公式
* @return BigDecimal 计算结果
*/
public static String execute(Map<String, String> data, String express) {
express = express.replaceAll("\\s", "");
List<String> expressWordArr = split(express);
Stack<String> dataStack = new Stack<>();
Stack<String> operatorStact = new Stack<>();
for (String expressWord : expressWordArr) {
if (!OPERATOR_LIST.contains(expressWord)) {
dataStack.push(expressWord);
} else {
if (operatorStact.isEmpty()) {
operatorStact.push(expressWord);
} else {
if ("(".equals(expressWord)) {
operatorStact.push(expressWord);
} else if (")".equals(expressWord)) {
// 括号内计算;
operatorStact.push(expressWord);
dalRightBracket(dataStack, operatorStact, data);
} else {
// 加减乘除
calculate(dataStack, operatorStact, expressWord, data);
}
}
}
}
while (!operatorStact.empty()) {
String operator = operatorStact.pop();
dal(dataStack, operator, data);
}
return data.get(dataStack.pop());
}
/**
* 解析关键词
* @param express 公式
* @return List<String> 拆分后的公式
*/
private static List<String> split(String express) {
List<String> list = new ArrayList<>();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < express.length(); i++) {
char c = express.charAt(i);
if (!OPERATOR_LIST.contains(String.valueOf(c))) {
builder.append(c);
} else {
list.add(builder.toString());
builder.delete(0, builder.length());
list.add(String.valueOf(c));
}
if (i == (express.length() - 1)) {
if (builder.length() > 0) {
list.add(builder.toString());
}
}
}
return list;
}
/**
* 括号内计算
* @param dataStack 数据栈
* @param operatorStact 操作栈
* @param s 操作符
* @param data 数据
*/
private static void calculate(Stack<String> dataStack, Stack<String> operatorStact, String s, Map<String, String> data) {
String oldOp = operatorStact.peek();
int oldOpNum = PRIORITY_MAP.get(oldOp);
int currentNum = PRIORITY_MAP.get(s);
if (oldOpNum >= currentNum) {
dal(dataStack, oldOp, data);
operatorStact.pop();
if (operatorStact.isEmpty()) {
operatorStact.push(s);
} else {
calculate(dataStack, operatorStact, s, data);
}
} else {
operatorStact.push(s);
}
}
/**
* 括号内计算
* @param dataStack 数据栈
* @param operatorStact 操作栈
* @param data 数据
*/
private static void dalRightBracket(Stack<String> dataStack, Stack<String> operatorStact, Map<String, String> data) {
while ( !operatorStact.empty() && ")".equals(operatorStact.peek())) {
String rightBracket = operatorStact.pop();
String tempOp = operatorStact.peek();
if ("(".equals(tempOp)) {
operatorStact.pop();
} else {
dal(dataStack, tempOp, data);
operatorStact.pop();
operatorStact.push(rightBracket);
}
}
}
/**
* 基础计算
* @param dataStack 数据栈
* @param operator 操作符
* @param data 数据
*/
private static void dal(Stack<String> dataStack, String operator, Map<String, String> data) {
String temp = dataStack.pop();
String oldTemp = dataStack.pop();
BigDecimal tempValue;
BigDecimal tempBigDecimal = new BigDecimal(data.get(temp));
BigDecimal oldTempBigDecimal = new BigDecimal(data.get(oldTemp));
switch (operator) {
case "+":
tempValue = oldTempBigDecimal.add(tempBigDecimal);
break;
case "-":
tempValue = oldTempBigDecimal.subtract(tempBigDecimal);
break;
case "*":
tempValue = oldTempBigDecimal.multiply(tempBigDecimal);
break;
case "/":
tempValue = oldTempBigDecimal.divide(tempBigDecimal, 16, BigDecimal.ROUND_HALF_UP);
break;
default:
throw new BaseRunTimeException("不支持的计算操作");
}
String uuid = String.valueOf(UUID.randomUUID());
data.put("tempValue-" + uuid, tempValue.toString());
dataStack.push("tempValue-" + uuid);
}
}
一个简单的公式计算,有需要的可以参考一下
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。