逻辑运算小工具
- 只支持逻辑运算
- 中缀表达式转后缀表达式
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.StringStack;
import java.util.*;
/**
* 公式计算类 使用公式进行逻辑运算
*/
public class Formula {
/**
* 使用空格分隔
*/
private final static String SPLIT_FLAG = " ";
/**
* 只支持逻辑运算
* @param expression 运算表达式
* @return 返回 true or false 如果计算出错直接抛异常 注意捕获异常自己处理失败逻辑,失败请仔细检查表达式
*/
public static boolean doExpression(String expression) {
Queue<String> postfixEx = getPostfixEx(expression);
/**
* 操作数栈
*/
Stack<Object> operandStack = new Stack<>();
while (!postfixEx.isEmpty()) {
String topOp = postfixEx.poll();
if (Operator.MAP.containsKey(topOp)) {
//是运算符
if (Operator.NOT.equals(topOp)) {
boolean pop = (boolean) operandStack.pop();
operandStack.push(!pop);
} else if (Arrays.asList(Operator.AND, Operator.OR).contains(topOp)) {
boolean right = (boolean) operandStack.pop();
boolean left = (boolean) operandStack.pop();
if (Operator.AND.equals(topOp)) {
operandStack.push(left && right);
} else if (Operator.OR.equals(topOp)) {
operandStack.push(left || right);
}
} else {
long right = Long.parseLong((String) operandStack.pop());
long left = Long.parseLong((String) operandStack.pop());
switch (topOp) {
case Operator.LT:
operandStack.push(left < right);
break;
case Operator.LE:
operandStack.push(left <= right);
break;
case Operator.GT:
operandStack.push(left > right);
break;
case Operator.GE:
operandStack.push(left >= right);
break;
case Operator.EQ:
operandStack.push(left == right);
break;
case Operator.NE:
operandStack.push(left != right);
break;
default:
//TODO 这个位置应该抛异常,在使用时自己修改
System.out.println("操作符不存在");
}
}
} else {
//是操作数
operandStack.push(topOp);
}
}
return (boolean) operandStack.pop();
}
/**
* 中缀表达式转后缀表达式
* 1、操作数直接入队列
* 2、左括号直接入运算符栈
* 3、运算符
* 如果运算符栈为空,入栈
* 如果运算符优先级小于于栈顶运算符,栈顶出栈入队列,当前运算符入栈
* 如果运算符优先级大于等于栈顶运算符,直接入栈
* 4、右括号
* 不入栈。将运算符栈出栈,入队列,直到遇到左括号,左括号出栈不入队列
* 5、中缀表达式遍历结算,将操作数栈全部出栈,入队列
* @param expression 表达式,要求:每个操作数和操作符之间用空格分隔 如:( 1 < 2 && ! ( 3 > 4 ) )
* @return 后缀表达式队列
*/
private static Queue<String> getPostfixEx(String expression) {
/**
* 后缀表达式
*/
Queue<String> postfixEx = new LinkedList<>();
/**
* 运算符栈
*/
StringStack operatorStack = new StringStack();
String[] ops = expression.split(SPLIT_FLAG);
for (String op : ops) {
op = op.trim();
if ("".equals(op)) {
continue;
}
if (Operator.LEFT.equals(op)) {
operatorStack.pushString(op);
} else if (Operator.RIGHT.equals(op)) {
while (!operatorStack.isEmpty() && !Operator.LEFT.equals(op = operatorStack.popString())) {
postfixEx.add(op);
}
} else if (Operator.MAP.containsKey(op)) {
if (!operatorStack.isEmpty()) {
String topOp = operatorStack.peekString();
if (Operator.comparePri(op, topOp)) {
//运算符优先级小于栈顶运算符,出栈,新运算符进栈
postfixEx.add(operatorStack.popString());
}
}
operatorStack.pushString(op);
} else {
postfixEx.add(op);
}
}
while (!operatorStack.isEmpty()) {
postfixEx.add(operatorStack.popString());
}
/*while (!postfixEx.isEmpty()) {
System.out.print(postfixEx.poll() + " ");
}*/
return postfixEx;
}
static class Operator {
/**
* 等于
*/
private final static String EQ = "==";
/**
* 不等于
*/
private final static String NE = "!=";
/**
* 大于
*/
private final static String GT = ">";
/**
* 大于等于
*/
private final static String GE = ">=";
/**
* 小于
*/
private final static String LT = "<";
/**
* 小于等于
*/
private final static String LE = "<=";
/**
* 左括号
*/
private final static String LEFT = "(";
/**
* 右括号
*/
private final static String RIGHT = ")";
private final static String AND = "&&";
private final static String OR = "||";
private final static String NOT = "!";
/**
* 优先级
*/
private final static int PRIORITY_0 = 0;
private final static int PRIORITY_1 = 1;
private final static int PRIORITY_2 = 2;
private final static int PRIORITY_3 = 3;
private static final Map<String, Integer> MAP;
static {
MAP = new HashMap<>();
MAP.put(GT, PRIORITY_2);
MAP.put(LT, PRIORITY_2);
MAP.put(EQ, PRIORITY_2);
MAP.put(GE, PRIORITY_2);
MAP.put(LE, PRIORITY_2);
MAP.put(NE, PRIORITY_2);
MAP.put(LEFT, PRIORITY_0);
MAP.put(RIGHT, PRIORITY_3);
MAP.put(AND, PRIORITY_1);
MAP.put(OR, PRIORITY_1);
MAP.put(NOT, PRIORITY_1);
}
/**
* 获取优先级
* @param op
* @return
*/
static int getPriority(String op) {
return MAP.get(op);
}
/**
* 比较优先级, 如果 op1 < op2 返回true
* @param op1
* @param op2
* @return
*/
static boolean comparePri(String op1, String op2) {
if (MAP.get(op1) < MAP.get(op2)) {
return true;
}
return false;
}
}
public static void main(String[] args) {
String rule = "{\n" +
"\t\"large\": \"( income >= 20000 )\",\n" +
"\t\"medium\": \"( income < 20000 && income >= 500 )\",\n" +
"\t\"small\": \"( income < 500 && income >= 50 )\",\n" +
"\t\"micro\": \"( income < 50 )\"\n" +
"}";
String rule1 = "{\n" +
"\t\"large\": \"( employee >= 1000 || income >= 40000 )\",\n" +
"\t\"medium\": \"( ( employee < 1000 || income < 40000 ) && employee >= 300 && income >= 2000 )\",\n" +
"\t\"small\": \"( ( employee < 300 || income < 2000 ) && employee >= 20 && income >= 300 )\",\n" +
"\t\"micro\": \"( employee < 20 || income < 300 )\"\n" +
"}";
String enterpriseSize = "medium";
Map<String, String> map = new HashMap<>();
map.put("employee", "300");
map.put("income", "2000");
map.put("capital", "100");
JSONObject ruleJson = JSONUtil.parseObj(rule1);
String expression = ruleJson.getStr(enterpriseSize);
for (String key : map.keySet()) {
expression = expression.replace(key, map.get(key));
}
System.out.println(Formula.doExpression(expression));
}
}