All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.lulihu.formula.ExpressionEvaluator Maven / Gradle / Ivy
package net.lulihu.formula;
import net.lulihu.ObjectKit.StrKit;
import net.lulihu.dateTime.DateTimeKit;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Stack;
/**
* 解析公式并返回结果的类
*/
public class ExpressionEvaluator {
/**
* @param expression 要计算的表达式,如"1+2+3+4"
* @return 返回计算结果, 如果带有逻辑运算符则返回true/false,否则返回数值
*/
public static Object eval(String expression) {
return CalcExpression(parseExpression(expression));
}
/**
* 评估三元运算
*
* @param expression 要计算的表达式
*/
public static Object evalThreeOperand(String expression) {
int index = expression.indexOf("?");
if (index > -1) {
String str = expression.substring(0, index);
String str2 = expression.substring(index + 1);
index = str2.indexOf(":");
if (Boolean.parseBoolean((CalcExpression(parseExpression(str))).toString())) {
return eval(str2.substring(0, index));
}
return eval(str2.substring(index + 1));
}
return CalcExpression(parseExpression(expression));
}
/**
* 将算术表达式转换为逆波兰表达式
*
* @param expression 要计算的表达式,如"1+2+3+4"
*/
private static List parseExpression(String expression) {
if (StrKit.isEmpty(expression)) {
return new ArrayList<>();
}
List listOperator = new ArrayList<>(10);
Stack stackOperator = new Stack<>();
ExpressionParser expParser = new ExpressionParser(expression);
ExpressionNode beforeExpNode; // 前一个节点
ExpressionNode unitaryNode = null; // 一元操作符
ExpressionNode expNode;
// 是否需要操作数
boolean requireOperand = false;
while ((expNode = expParser.readNode()) != null) {
if ((expNode.getType() == ExpressionNodeType.Numeric)
|| (expNode.getType() == ExpressionNodeType.String)
|| (expNode.getType() == ExpressionNodeType.Date)) {
// 操作数, 直接加入后缀表达式中
if (unitaryNode != null) {
// 设置一元操作符节点
expNode.setUnitaryNode(unitaryNode);
unitaryNode = null;
}
listOperator.add(expNode);
requireOperand = false;
} else if (expNode.getType() == ExpressionNodeType.LParentheses) {
// 左括号, 直接加入操作符栈
stackOperator.push(expNode);
} else if (expNode.getType() == ExpressionNodeType.RParentheses) {
// 右括号则在操作符栈中反向搜索,直到遇到匹配的左括号为止,将中间的操作符依次加到后缀表达式中。
ExpressionNode lpNode = null;
while (stackOperator.size() > 0) {
lpNode = stackOperator.pop();
if (lpNode.getType() == ExpressionNodeType.LParentheses)
break;
listOperator.add(lpNode);
}
if (lpNode == null || lpNode.getType() != ExpressionNodeType.LParentheses) {
throw new ExpressionException(String.format("在表达式\"%s\"中没有与在位置(%s)上\")\"匹配的\"(%s)\"字符!", expParser.getExpression(), expParser.getPosition()));
}
} else {
if (stackOperator.size() == 0) {
// 第一个节点则判断此节点是否是一元操作符"+,-,!,("中的一个,否则其它都非法
if (listOperator.size() == 0 && !(expNode.getType() == ExpressionNodeType.LParentheses
|| expNode.getType() == ExpressionNodeType.Not)) {
// 后缀表达式没有任何数据则判断是否是一元操作数
if (ExpressionNode.IsUnitaryNode(expNode.getType())) {
unitaryNode = expNode;
} else {
// 丢失操作数
throw new ExpressionException(String.format("表达式\"%s\"在位置(%s)上缺少操作数!",
expParser.getExpression(), expParser.getPosition()));
}
} else {
// 直接压入操作符栈
stackOperator.push(expNode);
}
requireOperand = true; // 下一个节点需要操作数
} else {
if (requireOperand) {
// 如果需要操作数则判断当前的是否是"+","-"号(一元操作符),如果是则继续
if (ExpressionNode.IsUnitaryNode(expNode.getType()) && unitaryNode == null) {
unitaryNode = expNode;
} else {
// 丢失操作数
throw new ExpressionException(String.format("表达式\"%s\"在位置({1})上缺少操作数!",
expParser.getExpression(), expParser.getPosition()));
}
} else {
// 对前面的所有操作符进行优先级比较
do {
// 取得上一次的操作符
beforeExpNode = stackOperator.peek();
// 如果前一个操作符优先级较高,则将前一个操作符加入后缀表达式中
if (beforeExpNode.getType() != ExpressionNodeType.LParentheses
&& (beforeExpNode.getPri() - expNode.getPri()) >= 0) {
listOperator.add(stackOperator.pop());
} else {
break;
}
} while (stackOperator.size() > 0);
// 将操作符压入操作符栈
stackOperator.push(expNode);
requireOperand = true;
}
}
}
}
if (requireOperand) {
// 丢失操作数
throw new ExpressionException(
String.format("表达式\"%s\"在位置({1})上缺少操作数!", expParser.getExpression(), expParser.getPosition()));
}
// 清空堆栈
while (stackOperator.size() > 0) {
// 取得操作符
beforeExpNode = stackOperator.pop();
if (beforeExpNode.getType() == ExpressionNodeType.LParentheses) {
throw new ExpressionException(String.format("表达式\"%s\"中括号不匹配,丢失右括号!", expParser.getExpression(),
expParser.getPosition()));
}
listOperator.add(beforeExpNode);
}
return listOperator;
}
/**
* 对逆波兰表达式进行计算
*
* @param nodes
* @return
*/
@SuppressWarnings({"rawtypes", "unchecked", "incomplete-switch"})
private static Object CalcExpression(List nodes) {
if (nodes == null || nodes.size() == 0)
return null;
if (nodes.size() > 1) {
int index = 0;
// 储存数据
ArrayList values = new ArrayList();
while (index < nodes.size()) {
ExpressionNode node = nodes.get(index);
switch (node.getType()) {
// 如果是数字,则将值存入 values 中
case Numeric:
case String:
case Date:
values.add(node.getNumeric());
index++;
break;
default:
// 二元表达式,需要二个参数, 如果是Not的话,则只要一个参数
int paramCount = 2;
if (node.getType() == ExpressionNodeType.Not)
paramCount = 1;
// 计算操作数的值
if (values.size() < paramCount) {
throw new ExpressionException("缺少操作数");
}
// 传入参数
Object[] data = new Object[paramCount];
for (int i = 0; i < paramCount; i++) {
data[i] = values.get(index - paramCount + i);
}
// 将计算结果再存入当前节点
node.setNumeric(calculate(node.getType(), data));
node.setType(ExpressionNodeType.Numeric);
// 将操作数节点删除
for (int i = 0; i < paramCount; i++) {
nodes.remove(index - i - 1);
values.remove(index - i - 1);
}
index -= paramCount;
break;
}
}
}
if (nodes.size() != 1) {
throw new ExpressionException("缺少操作符或操作数");
}
switch (nodes.get(0).getType()) {
case Numeric:
return nodes.get(0).getNumeric();
case String:
case Date:
return nodes.get(0).getNumeric().toString().replace("\"", "");
}
throw new ExpressionException("缺少操作数");
}
/**
* 计算节点的值
*
* @param nodeType 节点的类型
* @param data 要计算的值,有可能是两位或一位数
* @return
*/
@SuppressWarnings("incomplete-switch")
private static Object calculate(ExpressionNodeType nodeType, Object[] data) {
double d1, d2;
boolean b1, b2;
Date time1, time2;
Object obj1 = data[0];
Object obj2 = data[1];
String str1 = obj1.toString();
String str2 = obj2.toString();
boolean dateflag = ExpressionNode.isDatetime(str1) || ExpressionNode.isDatetime(str2);
boolean strflag = str1.contains("\"") || str2.contains("\"");
str1 = str1.replace("\"", "");
str2 = str2.replace("\"", "");
switch (nodeType) {
case Plus:
if (!strflag) {
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 + d2);
}
return new StringBuffer(str1 + str2).toString();
case Subtract:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return d1 - d2;
case MultiPly:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return d1 * d2;
case Divide:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
if (d2 == 0)
throw new RuntimeException();
return d1 / d2;
case Power:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return Math.pow(d1, d2);
case Mod:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
if (d2 == 0)
throw new RuntimeException();
return d1 % d2;
case BitwiseAnd:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (int) d1 & (int) d2;
case BitwiseOr:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (int) d1 | (int) d2;
case And:
b1 = ConvertToBool(obj1);
b2 = ConvertToBool(obj2);
return b1 && b2;
case Or:
b1 = ConvertToBool(obj1);
b2 = ConvertToBool(obj2);
return b1 || b2;
case Not:
b1 = ConvertToBool(obj1);
return !b1;
case Equal:
if (!dateflag) {
if (strflag) {
return str1.equals(str2);
}
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 == d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() == time2.getTime());
case Unequal:
if (!dateflag) {
if (strflag) {
return (!str1.equals(str2));
}
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 != d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() != time2.getTime());
case GT:
if (!dateflag) {
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 > d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() > time2.getTime());
case LT:
if (!dateflag) {
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 < d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() < time2.getTime());
case GTOrEqual:
if (!dateflag) {
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 >= d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() >= time2.getTime());
case LTOrEqual:
if (!dateflag) {
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 <= d2);
}
time1 = DateTimeKit.parseDate(str1);
time2 = DateTimeKit.parseDate(str2);
return (time1.getTime() <= time2.getTime());
case LShift:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (long) d1 << (int) d2;
case RShift:
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (long) d1 >> (int) d2;
case Like:
if (!strflag) {
return false;
}
return str1.contains(str2);
case NotLike:
if (!strflag) {
return false;
}
return !str1.contains(str2);
case StartWith:
if (!strflag) {
return false;
}
return str1.startsWith(str2);
case EndWith:
if (!strflag) {
return false;
}
return str1.endsWith(str2);
}
return 0;
}
/**
* 某个值转换为bool值
*
* @param value
* @return
*/
private static Boolean ConvertToBool(Object value) {
if (value instanceof Boolean) {
return (Boolean) value;
} else {
return value != null;
}
}
/**
* 将某个值转换为decimal值
*
* @param value
*/
private static Double ConvertToDecimal(Object value) {
if (value instanceof Boolean) {
return ((Boolean) value ? 1d : 0d);
} else {
return Double.parseDouble(value.toString());
}
}
}