之前简单的介绍了这个基于Java表达式解析工具,现在把代码分享给大家,希望帮助到有需要的人们,这个分享代码中依赖了一些其他的类,这些类大家可以根据自己的情况进行导入,无非就是写字符串处理工具类,日期处理的工具类什么的。
这个Java的表达式解析的工具只用了5个类,而且写得也很简单明了,相信有一些编程经验的可以看懂这些处理的逻辑代码。
1、第一个类:ExpressionNodeType(表达式各个字符节点的类型枚举类)
public enum ExpressionNodeType {
Unknown,
Plus,// +
Subtract, /// -
MultiPly,// *
Divide,// /
LParentheses,//(
RParentheses, /// )
Mod,//% (求模,取余)
Power,// ^ (次幂)
BitwiseAnd, /// & (按位与)
BitwiseOr,/// | (按位或)
And,// && (逻辑与)
Or, /// || (逻辑或)
Not,/// ! (逻辑非)
Equal,/// == (相等)
Unequal,/// != 或 <> (不等于)
GT, /// > (大于)
LT, /// < (小于)
GTOrEqual,/// >= (大于等于)
LTOrEqual, /// <= (小于等于)
LShift, /// << (左移位)
RShift,/// >> (右移位)
Numeric, /// 数值,
String,
Date,
Like,//包含
NotLike,//不包含
StartWith,//已什么开始
EndWith//已什么结尾
}
这个类中定义了一些枚举的类型,如加减乘数啊,等于不等于啊,包含不包含啊,如果要进行扩展的话,第一步需要在这里定义一种枚举类型。
2、第二个类:ExpressionNode(存储表达式运算符或操作数的各个节点的类)
public class ExpressionNode {
private String value;
private ExpressionNodeType type;
private int pri;
private ExpressionNode unitaryNode;
private Object numeric;
/**
*
* @param value 操作数或运算符
*/
public ExpressionNode(String value)
{
this.value = value;
this.type = parseNodeType(value);
this.pri = getNodeTypePRI(this.type);
this.numeric = null;
}
public Object getNumeric(){
if(this.numeric == null){
if ((this.type == ExpressionNodeType.String) || (this.type == ExpressionNodeType.Date))
{
return this.value;
}
if (this.type != ExpressionNodeType.Numeric){
return 0;
}
Double num = new Double(this.value);
if (this.unitaryNode != null && this.unitaryNode.type == ExpressionNodeType.Subtract)
{
num = 0 - num;
}
this.numeric = num;
}
return numeric;
}
public void setNumeric(Object numeric) {
this.numeric = numeric;
this.value = this.numeric.toString();
}
/**
* 设置或返回与当前节点相关联的一元操作符节点
* @param unitaryNode
*/
public void setUnitaryNode(ExpressionNode unitaryNode) {
this.unitaryNode = unitaryNode;
}
/**
* 解析节点类型
* @param value
* @return
*/
private static ExpressionNodeType parseNodeType(String value)
{
if (StringUtils.isEmpty(value)){
return ExpressionNodeType.Unknown;
}
switch (value)
{
case "+":
return ExpressionNodeType.Plus;
case "-":
return ExpressionNodeType.Subtract;
case "*":
return ExpressionNodeType.MultiPly;
case "/":
return ExpressionNodeType.Divide;
case "%":
return ExpressionNodeType.Mod;
case "^":
return ExpressionNodeType.Power;
case "(":
return ExpressionNodeType.LParentheses;
case ")":
return ExpressionNodeType.RParentheses;
case "&":
return ExpressionNodeType.BitwiseAnd;
case "|":
return ExpressionNodeType.BitwiseOr;
case "&&":
case "<并且>":
case "并且":
return ExpressionNodeType.And;
case "||":
case "<或者>":
case "或者":
return ExpressionNodeType.Or;
case "!":
return ExpressionNodeType.Not;
case "==":
case "=":
return ExpressionNodeType.Equal;
case "!=":
case "<>":
case "≠":
return ExpressionNodeType.Unequal;
case ">":
return ExpressionNodeType.GT;
case "<":
return ExpressionNodeType.LT;
case ">=":
case "≥":
return ExpressionNodeType.GTOrEqual;
case "<=":
case "≤":
return ExpressionNodeType.LTOrEqual;
case "<<":
return ExpressionNodeType.LShift;
case ">>":
return ExpressionNodeType.RShift;
case "@":
case "<包含>":
case "包含":
return ExpressionNodeType.Like;
case "!@":
case "<不包含>":
case "不包含":
return ExpressionNodeType.NotLike;
case "!!$":
return ExpressionNodeType.StartWith;
case "!!@":
return ExpressionNodeType.EndWith;
}
if (isNumerics(value))
{
return ExpressionNodeType.Numeric;
}
if (isDatetime(value))
{
return ExpressionNodeType.Date;
}
if (value.contains("\""))
{
return ExpressionNodeType.String;
}
return ExpressionNodeType.Unknown;
}
/**
* 获取各节点类型的优先级
* @param nodeType
* @return
*/
private static int getNodeTypePRI(ExpressionNodeType nodeType)
{
switch (nodeType)
{
case LParentheses:
case RParentheses:
return 9;
//逻辑非是一元操作符,所以其优先级较高
case Not:
return 8;
case Mod:
return 7;
case MultiPly:
case Divide:
case Power:
return 6;
case Plus:
case Subtract:
return 5;
case LShift:
case RShift:
return 4;
case BitwiseAnd:
case BitwiseOr:
return 3;
case Equal:
case Unequal:
case GT:
case LT:
case GTOrEqual:
case LTOrEqual:
case Like:
case NotLike:
case StartWith:
case EndWith:
return 2;
case And:
case Or:
return 1;
default:
return 0;
}
}
/**
* 判断是否为数值
* @param op
* @return
*/
public static boolean isNumerics(String op)
{
return op.matches("^[\\+\\-]?(0|[1-9]\\d*|[1-9]\\d*\\.\\d+|0\\.\\d+)");
}
/**
* 判断是否为日期
* @param op
* @return
*/
public static boolean isDatetime(String op)
{
op = op.replace("\"","").trim();
return op.matches("\\d{4}\\-\\d{2}\\-\\d{2}(\\s\\d{2}\\:\\d{2}\\:\\d{2})?");
}
/**
* 判断某个字符后是否需要更多的操作符
* @param c
* @return
*/
public static boolean needMoreOperator(char c)
{
switch (c)
{
case '&':
case '|':
case '=':
case '!':
case '>':
case '<':
case '.': //小数点
return true;
}
// //数字则需要更多
return Character.isDigit(c);
}
/**
* 判断两个字符是否是同一类
* @param c1
* @param c2
* @return
*/
public static boolean IsCongener(char c1, char c2)
{
if ((c1 == '(') || (c2 == '(')){
return false;
}
if ((c1 == ')') || (c2 == ')')){
return false;
}
if ((c1 == '"') || (c2 == '"')){
return false;
}
if (Character.isDigit(c1) || (c1 == '.'))
{
//c1为数字,则c2也为数字
return (Character.isDigit(c2) || (c2 == '.'));
}
return (!Character.isDigit(c2) && (c2 != '.'));
}
/**
* 判断某个字符是否是空白字符
* @param c
* @return
*/
public static boolean IsWhileSpace(char c)
{
return c == ' ' || c == '\t';
}
/**
* 判断是否是一元操作符节点
* @param nodeType
* @return
*/
public static boolean IsUnitaryNode(ExpressionNodeType nodeType)
{
return (nodeType == ExpressionNodeType.Plus || nodeType == ExpressionNodeType.Subtract);
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public ExpressionNodeType getType() {
return type;
}
public void setType(ExpressionNodeType type) {
this.type = type;
}
public int getPri() {
return pri;
}
public void setPri(int pri) {
this.pri = pri;
}
public ExpressionNode getUnitaryNode() {
return unitaryNode;
}
3、第三个类:ExpressionException(表达式异常类)
public class ExpressionException extends RuntimeException{
private static final long serialVersionUID = 1L;
public ExpressionException() {
super();
}
public ExpressionException(String msg) {
super(msg);
}
public ExpressionException(String msg, Throwable cause) {
super(msg,cause);
}
public ExpressionException(Throwable cause) {
super(cause);
}
}
public class ExpressionParser {
//当前分析的表达式
private String expression;
//当前读取的位置
private int position;
public String getExpression() {
return expression;
}
public void setExpression(String expression) {
this.expression = expression;
}
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
public ExpressionParser(String expression)
{
this.expression = expression;
this.position = 0;
}
/**
* 读取下一个表达式节点,如果读取失败则返回null
* @return
*/
public ExpressionNode readNode()
{
//空格的位置
int whileSpacePos = -1;
boolean flag = false;
StringBuffer buffer = new StringBuffer(10);
while (this.position < this.expression.length())
{
char c = this.expression.charAt(this.position);
if (c == '"')
{
flag = !flag;
if (!flag)
{
this.position++;
buffer.append(c);
break;
}
if (buffer.length() != 0)
{
break;
}
}
if (flag)
{
this.position++;
buffer.append(c);
}
else
{
if (ExpressionNode.IsWhileSpace(c))
{
if ((whileSpacePos >= 0) && ((this.position - whileSpacePos) > 1))
{
throw new ExpressionException(String.format("表达式\"%s\"在位置(%s)上的字符非法!", this.getExpression(), this.getPosition()));
}
if (buffer.length() == 0)
{
whileSpacePos = -1;
}
else
{
whileSpacePos = this.position;
}
this.position++;
continue;
}
if ((buffer.length() == 0) || ExpressionNode.IsCongener(c, buffer.charAt(buffer.length() - 1)))
{
this.position++;
buffer.append(c);
}
else
{
break;
}
if (!ExpressionNode.needMoreOperator(c))
{
break;
}
}
}
if (buffer.length() == 0)
{
return null;
}
ExpressionNode node = new ExpressionNode(buffer.toString());
if (node.getType() == ExpressionNodeType.Unknown)
{
throw new ExpressionException(String.format("表达式\"%s\"在位置%s上的字符\"%s\"非法!", this.getExpression(), this.getPosition() - node.getValue().length(), node.getValue()));
}
return node;
}
}
5、第五个类:ExpressionEvaluator(解析公式并返回结果的类)
public class ExpressionEvaluator {
private ExpressionEvaluator()
{
}
/**
* 将算术表达式转换为逆波兰表达式
* @param expression 要计算的表达式,如"1+2+3+4"
* @return
*/
private static List parseExpression(String expression)
{
if(StringUtils.isEmpty(expression)){
return new ArrayList();
}
List listOperator = new ArrayList(10);
Stack stackOperator = new Stack();
ExpressionParser expParser = new ExpressionParser(expression);
ExpressionNode beforeExpNode = null; //前一个节点
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;
continue;
}
else if (expNode.getType() == ExpressionNodeType.LParentheses)
{
//左括号, 直接加入操作符栈
stackOperator.push(expNode);
continue;
}
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; //下一个节点需要操作数
continue;
}
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
*/
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
*/
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((double)d1, (double)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 = DateUtils.parse(str1);
time2 = DateUtils.parse(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 = DateUtils.parse(str1);
time2 = DateUtils.parse(str2);
return (time1.getTime() != time2.getTime());
case GT:
if (!dateflag)
{
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 > d2);
}
time1 = DateUtils.parse(str1);
time2 = DateUtils.parse(str2);
return (time1.getTime() > time2.getTime());
case LT:
if (!dateflag)
{
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 < d2);
}
time1 = DateUtils.parse(str1);
time2 = DateUtils.parse(str2);
return (time1.getTime() < time2.getTime());
case GTOrEqual:
if (!dateflag)
{
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 >= d2);
}
time1 = DateUtils.parse(str1);
time2 = DateUtils.parse(str2);
return (time1.getTime() >= time2.getTime());
case LTOrEqual:
if (!dateflag)
{
d1 = ConvertToDecimal(obj1);
d2 = ConvertToDecimal(obj2);
return (d1 <= d2);
}
time1 = DateUtils.parse(str1);
time2 = DateUtils.parse(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
* @return
*/
private static Double ConvertToDecimal(Object value)
{
if (value instanceof Boolean)
{
return ((Boolean)value ? 1d : 0d);
}
else
{
return Double.parseDouble(value.toString());
}
}
/**
*
* @param expression 要计算的表达式,如"1+2+3+4"
* @return 返回计算结果,如果带有逻辑运算符则返回true/false,否则返回数值
*/
public static Object eval(String expression)
{
return CalcExpression(parseExpression(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));
}
}
这个工具的介绍就这些了,希望可以帮助到有需要的人。