
cn.handyplus.lib.core.FormulaUtil Maven / Gradle / Ivy
The newest version!
package cn.handyplus.lib.core;
import cn.handyplus.lib.constants.BaseConstants;
import cn.handyplus.lib.exception.HandyException;
import java.math.BigDecimal;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Matcher;
/**
* 公式工具类
*
* @author handy
* @since 3.7.0
*/
public class FormulaUtil {
private FormulaUtil() {
}
/**
* 进行计算
*
* @param formula 公式
* @param map 替换数据
* @return 计算结果
*/
public static Long evaluateFormulaToLong(String formula, Map map) {
return NumberUtil.isNumericToLong(evaluateFormula(formula, map), 0L);
}
/**
* 进行计算
*
* @param formula 公式
* @param map 替换数据
* @return 计算结果
*/
public static Double evaluateFormulaToDouble(String formula, Map map) {
return NumberUtil.isNumericToDouble(evaluateFormula(formula, map), 0.0);
}
/**
* 进行计算
*
* @param formula 公式
* @param map 替换数据
* @return 计算结果
*/
public static Integer evaluateFormulaToInt(String formula, Map map) {
return evaluateFormulaToDouble(formula, map).intValue();
}
/**
* 进行计算
*
* @param formula 公式
* @param map 替换数据
* @return 计算结果
*/
public static String evaluateFormula(String formula, Map map) {
Matcher matcher = BaseConstants.TEMPLATE_EXPRESSION_REGEX.matcher(formula);
String variable;
while (matcher.find()) {
variable = matcher.group(1);
formula = StrUtil.replace(formula, variable, BaseConstants.TEMPLATE_EXPRESSION_VALUE);
// 替换变量数据
for (String key : map.keySet()) {
variable = variable.replace(key, map.get(key));
}
// 计算公式结果
String result = calculateExpression(variable);
formula = formula.replace(BaseConstants.TEMPLATE_EXPRESSION_VALUE, result);
}
return formula;
}
/**
* 使用Script 进行计算
*
* @param expression 表达式
* @return 计算结果
*/
private static String calculateExpression(String expression) {
String rpn = toRPN(expression);
return String.valueOf(calculateRPN(rpn));
}
/**
* 将中缀表达式转换为逆波兰表达式
*
* @param expression 表达式
* @return 逆波兰表达式
*/
private static String toRPN(String expression) {
StringBuilder rpn = new StringBuilder();
Stack stack = new Stack<>();
for (int i = 0; i < expression.length(); i++) {
char c = expression.charAt(i);
// 如果是空格,则忽略
if (c == ' ') {
continue;
}
// 如果是数字,则直接输出
if (Character.isDigit(c)) {
while (i < expression.length() && (Character.isDigit(expression.charAt(i)) || expression.charAt(i) == '.')) {
rpn.append(expression.charAt(i));
i++;
}
rpn.append(' ');
i--;
}
// 如果是左括号,则入栈
else if (c == '(') {
stack.push(c);
}
// 如果是右括号,则将栈顶的运算符弹出并输出,直到遇到左括号
else if (c == ')') {
while (!stack.isEmpty() && stack.peek() != '(') {
rpn.append(stack.pop()).append(' ');
}
// 弹出左括号
stack.pop();
}
// 如果是运算符,则判断其与栈顶运算符的优先级
else if (isOperator(c)) {
while (!stack.isEmpty() && getPriority(stack.peek()) >= getPriority(c)) {
rpn.append(stack.pop()).append(' ');
}
stack.push(c);
}
}
// 将栈中剩余的运算符弹出并输出
while (!stack.isEmpty()) {
rpn.append(stack.pop()).append(' ');
}
return rpn.toString();
}
/**
* 判断是否是运算符
*
* @param c 字符
* @return true
*/
private static boolean isOperator(char c) {
return c == '+' || c == '-' || c == '*' || c == '/';
}
/**
* 获取运算符的优先级
*
* @param operator 运算符
* @return 级别
*/
private static int getPriority(char operator) {
switch (operator) {
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
default:
return 0;
}
}
/**
* 计算逆波兰表达式的结果
*
* @param rpn 逆波兰表达式
* @return 结果
*/
private static double calculateRPN(String rpn) {
Stack stack = new Stack<>();
String[] tokens = rpn.split(" ");
for (String token : tokens) {
if (isNumber(token)) {
stack.push(Double.parseDouble(token));
} else if (isOperator(token.charAt(0))) {
double operand2 = stack.pop();
double operand1 = stack.pop();
double result = performOperation(operand1, operand2, token.charAt(0));
stack.push(result);
}
}
return stack.pop();
}
/**
* 判断是否是数字
*
* @param token 字符
* @return true
*/
private static boolean isNumber(String token) {
try {
Double.parseDouble(token);
return true;
} catch (NumberFormatException e) {
return false;
}
}
/**
* 执行运算操作
*
* @param operand1 操作数1
* @param operand2 操作数2
* @param operator 操作数3
* @return 结果
*/
private static double performOperation(double operand1, double operand2, char operator) {
BigDecimal bigDecimalOperand1 = BigDecimal.valueOf(operand1);
BigDecimal bigDecimalOperand2 = BigDecimal.valueOf(operand2);
switch (operator) {
case '+':
return bigDecimalOperand1.add(bigDecimalOperand2).doubleValue();
case '-':
return bigDecimalOperand1.subtract(bigDecimalOperand2).doubleValue();
case '*':
return bigDecimalOperand1.multiply(bigDecimalOperand2).doubleValue();
case '/':
if (operand2 == 0) {
throw new HandyException("除数不能为0");
}
return bigDecimalOperand1.divide(bigDecimalOperand2, 2, BigDecimal.ROUND_HALF_UP).doubleValue();
default:
throw new HandyException("不支持的运算符: " + operator);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy