Java realizes the calculation of complex logic expressions

I recently encountered a demand that requires calculation of logical expressions. The supported data types include numbers, dates and strings. The operators include <,<=,>,>=,(,),==,!=,&&, ||.

Code structure:

  OperatorEnum operator enumeration class enumerates the supported operators, information including operators and their priority

  OperandTypeEnum data type enumeration class

  LogicUtil logic operation tool class, realize logic operation

  DateUtil date tool class, which provides methods to verify whether it is a date and compare the size, see https://www.cnblogs.com/lin0/p/13323925.html

(Subsequently, the code for judging whether the expression is legal is added to the realization of the logical expression, the parentheses do not match, the data types on both sides of the operator are inconsistent, the logical expression is incomplete, etc., which is not pasted)

OperatorEnum:

import java.util.HashMap;
import java.util.Map;

public enum OperatorEnum {
    //!,&,|运算时暂时未考虑在内,主要用于判断字符是否为操作
    NOT("!",0),
    LT("<",1),
    ELT("<=",1),
    GT(">",1),
    EGT(">=",1),
    EQ("==",2),
    NEQ("!=",2),
    BAND("&", 3),
    BOR("|", 4),
    AND("&&",5),
    OR("||",6),
    E("=", 7);
    private String name;
    private Integer priority;
    OperatorEnum(String name, Integer priority){
        this.name = name;
        this.priority = priority;
    }

    private static Map<String, OperatorEnum> enums = new HashMap<>();
    public static void enumToMap(){
        enums.put("!", OperatorEnum.NOT);
        enums.put("<", OperatorEnum.LT);
        enums.put("<=", OperatorEnum.ELT);
        enums.put(">", OperatorEnum.GT);
        enums.put(">=", OperatorEnum.EGT);
        enums.put("==", OperatorEnum.EQ);
        enums.put("!=", OperatorEnum.NEQ);
        enums.put("&", OperatorEnum.BAND);
        enums.put("|", OperatorEnum.BOR);
        enums.put("&&", OperatorEnum.AND);
        enums.put("||", OperatorEnum.OR);
        enums.put("=", OperatorEnum.E);
    }

    public static OperatorEnum getEnumByName(String name){
        if(enums.size() < 1){
            enumToMap();
        }
        return enums.get(name);
    }

    public static boolean isOperator(String name){
        if(enums.size() < 1){
            enumToMap();
        }
        return enums.containsKey(name);
    }

    public Integer getPriority() {
        return priority;
    }

    public String getName() {
        return name;
    }

}

OperandTypeEnum :

public enum OperandTypeEnum {
    NUM("数字"),
    DATE("日期"),
    STR("字符串");
    private String typeName;
    OperandTypeEnum(String typeName){
        this.typeName = typeName;
    }
}

DateUse :

/**
     * @author Carol
     * 比较日期大小
     * @return
     */
    public static int compareDate(String date1, String date2){
        String d1 = date1.trim().replaceAll("-|:|/| ","");
        String d2 = date2.trim().replaceAll("-|:|/| ", "");
        StringBuilder sb1 = new StringBuilder(d1);
        StringBuilder sb2 = new StringBuilder(d2);
        while(sb1.length() < 14){
            sb1.append("0");
        }
        while(sb2.length() < 14){
            sb2.append("0");
        }
        long num1 = Long.parseLong(sb1.toString());
        long num2 = Long.parseLong(sb2.toString());
        return num1 == num2 ? 0 : num1 > num2 ? 1 : -1;
    }

LogicUtil;

/**
     * @author Carol
     * 计算表达式
     * 利用一个操作数栈和一个操作栈来进行计算
     * 出栈情况:当前字符串为操作并且优先级小于栈顶操作元素或者遇到“)”,将操作栈中栈顶元素出栈,操作数栈中出栈俩元素
     * 入栈情况:“(”直接入栈,或者当前操作优先级大于栈顶元素则直接入栈,操作数直接入栈
     * @param expression
     * @return
     */
    public static boolean parse2(String expression) {
        Deque<String> operands = new LinkedList<>();//操作数栈
        Deque<String> operate = new LinkedList<>();//操作栈
        StringBuilder sb = new StringBuilder();
        try {
            byte[] bytes = expression.getBytes("GBK");
            for (int i = 0 ; i < bytes.length ; i ++) {
                //汉字
                if (bytes[i] < 0) {
                    if (i == bytes.length - 1) {//字符串异常截断
                        //不要这个字
                    } else {
                        sb.append(new String(new byte[]{bytes[i], bytes[i + 1]}, "GBK"));
                        i ++;
                    }
                    continue;
                }
                String thisOp = new String(new byte[]{bytes[i]});
                //直接入栈
                if ("(".equals(thisOp)) {
                    pushOperandIntoStack(operands, sb);
                    operate.addFirst(thisOp);
                    continue;
                }
                //到“(”之前的全部出栈
                if (")".equals(thisOp)) {
                    pushOperandIntoStack(operands, sb);
                    String topOp = operate.pollFirst();
                    while(!"(".equals(topOp)){
                        calculate(operands, topOp);
                        if (operate.size() > 0) {
                            topOp = operate.pollFirst();
                        } else {
                            //括号没匹配上,逻辑表达式出错
                            return false;
                        }

                    }
                    continue;
                }
                if (OperatorEnum.isOperator(thisOp)) {//当前是否为操作符
                    //是,1.查看之前是否有字符未入栈,先入栈字符
                    pushOperandIntoStack(operands, sb);
                    //2.查看下一个是否为操作,并且非括号,是合并当前一起入操作栈
                    String nextOp = new String(new byte[]{bytes[i + 1]});
                    //下个与当前一起组成一个操作
                    if (!"(".equals(nextOp) && !")".equals(nextOp) && OperatorEnum.isOperator(nextOp)) {
                        thisOp += nextOp;
                        i ++;
                    }
                    //判断当前操作与栈顶操作优先级
                    if(operate.size() > 0){
                        String topOp = operate.getFirst();
                        while(!"(".equals(topOp) && OperatorEnum.getEnumByName(topOp).getPriority() < OperatorEnum.getEnumByName(thisOp).getPriority()){
                            //优先级高,出栈进行计算
                            topOp = operate.pollFirst();
                            calculate(operands, topOp);
                            if (operate.size() > 0) {
                                topOp = operate.getFirst();
                            } else {
                                break;
                            }

                        }
                    }
                    operate.addFirst(thisOp);
                } else {
                    sb.append(thisOp);
                }
            }
        } catch (Exception e){
            e.printStackTrace();
        }
        if(sb.length() > 0){
            operands.addFirst(sb.toString());
        }
        while(operate.size() > 0){
            String topOp = operate.pollFirst();
            calculate(operands, topOp);
        }
        if (operands.size() > 0){
            String str = operands.pollFirst();
            return StringUtils.isNotBlank(str) ? Boolean.parseBoolean(str) : false;
        }
        return false;
    }

    private static void pushOperandIntoStack(Deque operands, StringBuilder sb){
        if(sb.length() > 0){
            operands.addFirst(sb.toString());
            sb.setLength(0);
        }
    }

    private static void calculate(Deque<String> operands, String topOp){
        String operand2 = operands.pollFirst().trim();
        String operand1 = operands.pollFirst().trim();
        //判断两个操作数类型,不一致不可比较直接返回false
        OperandTypeEnum type1 = judgeType(operand1);
        OperandTypeEnum type2 = judgeType(operand2);
        if (type1 == type2) {
            switch (type1){
                case NUM:
                    operands.addFirst(numCalculate(Long.parseLong(operand1), Long.parseLong(operand2),
                            OperatorEnum.getEnumByName(topOp)) + "");
                    break;
                case DATE:
                    operands.addFirst(dateCalculate(operand1, operand2, OperatorEnum.getEnumByName(topOp)) + "");
                    break;
                case STR:
                    operands.addFirst(strCalculate(operand1, operand2, OperatorEnum.getEnumByName(topOp)) + "");
                    break;
            }
        } else {
            operands.addFirst("false");
        }
    }

    private static OperandTypeEnum judgeType (String operands) {
        operands = operands.trim();
        if (Pattern.matches("^[-\\+]?[\\d]*$", operands)) {
            return OperandTypeEnum.NUM;
        }
        if (DateUtil.verifyDateLegal(operands)) {
            return OperandTypeEnum.DATE;
        }
        return OperandTypeEnum.STR;
    }

    private static boolean numCalculate(long operand1, long operand2, OperatorEnum operate){
        switch (operate){
            case LT:
                return operand1 < operand2;
            case ELT:
                return operand1 <= operand2;
            case GT:
                return operand1 > operand2;
            case EGT:
                return operand1 >= operand2;
            case EQ:
                return operand1 == operand2;
            case NEQ:
                return operand1 != operand2;
            default:
                return true;
        }
    }

    private static boolean strCalculate(String operand1, String operand2, OperatorEnum operate){
        switch (operate){
            case EQ:
                return operand1.equals(operand2);
            case NEQ:
                return !operand1.equals(operand2);
            case AND:
                return "true".equals(operand1) && "true".equals(operand2);
            case OR:
                return "true".equals(operand1) || "true".equals(operand2);
            default:
                return true;
        }
    }

    private static boolean dateCalculate(String operand1, String operand2, OperatorEnum operate){
        switch (operate){
            case LT:
                return DateUtil.compareDate(operand1, operand2) == -1 ? true : false;
            case ELT:
                return DateUtil.compareDate(operand1, operand2) <= 0 ? true : false;
            case GT:
                return DateUtil.compareDate(operand1, operand2) == 1 ? true : false;
            case EGT:
                return DateUtil.compareDate(operand1, operand2) >= 0 ? true : false;
            case EQ:
                return DateUtil.compareDate(operand1, operand2) == 0 ? true : false;
            case NEQ:
                return DateUtil.compareDate(operand1, operand2) != 0 ? true : false;
            default:
                return true;
        }
    }

Test code:

System.out.println( LogicUtil.parse2("2==3 && 2==2 || 3==3"));
       System.out.println("true == " +  parse2("3>2"));
       System.out.println("false == " + parse2("true == false"));
       System.out.println("false == " + parse2("(3<2||2==2)&&(4==5)"));
       System.out.println("false == " + parse2("(abc==fdg||民事==民事&&嘻嘻==嘻ha)&&(4>2||5<10)"));
       System.out.println("true == " + parse2("()(((abc!=fdg||民事==民事&&嘻嘻==嘻ha)&&(4>2||5<10)))"));
       System.out.println("true == " + parse2("5 < 19"));
       System.out.println("false == " + parse2("5 > 19"));

Test Results:

 

 

 

Guess you like

Origin blog.csdn.net/a159357445566/article/details/108588614
Recommended