• java 实现逻辑表达式解析


    java 实现逻辑表达式解析

    老黄瓜001

    于 2020-07-28 17:16:30 发布

    这里的字符串分割使用的默认空格分隔,使用时需要特别注意模板格式。

    废话不多说,直接上代码

    package com.lunua.parse;
     
    import com.alibaba.fastjson.JSONPath;
    import com.google.common.collect.Lists;
     
    import java.util.ArrayList;
    import java.util.EmptyStackException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Stack;
     
    public class Parser {
        enum Op{
            GT(">"),GE(">="),LT("<"),LE("<="),EQ("=="),AND("and"),OR("or"),CONTAINS("contains"),CONTAINS_NOT("containsnot");
            private String operator;
     
            Op(String operator) {
                this.operator = operator;
            }
     
            public String getOperator() {
                return operator;
            }
            public static Op getByOperator(String operator){
                if (operator == null || operator.length() == 0){
                    return null;
                }
                for (Op op: Op.values()) {
                    if (op.getOperator().equalsIgnoreCase(operator)){
                        return op;
                    }
                }
                return null;
            }
        }
     
     
     
        private static final List<String> operator = Lists.newArrayList(Op.GT.getOperator(), Op.GE.getOperator(), Op.LT.getOperator(),Op.LE.getOperator(),Op.EQ.getOperator(),Op.AND.getOperator(),Op.OR.getOperator(),Op.CONTAINS.getOperator(),Op.CONTAINS_NOT.getOperator());
        private static Map<String, Integer> operatorMap = null;
        static {
            operatorMap = new HashMap<String, Integer>();
            operatorMap.put("(", 1);
            operatorMap.put(")", 1);
            operatorMap.put("and", 11);
            operatorMap.put("or", 12);
            operatorMap.put("==", 7);
            operatorMap.put("!=", 7);
            operatorMap.put(">", 6);
            operatorMap.put(">=", 6);
            operatorMap.put("<", 6);
            operatorMap.put("<=", 6);
            operatorMap.put("contains",14);
            //operatorMap.put("containsNot",14);
            operatorMap.put("containsnot",14);
        }
     
        private ArrayList<String> getTokens(String pattern){
            String[] splitArr = pattern.split(" ");
            ArrayList<String> tokens = new ArrayList<String>();
            for (String split:splitArr) {
                String trim = split.trim();
                if (trim != null && trim.length() != 0){
                    tokens.add(trim);
                }
            }
            return tokens;
        }
        /**
         * 计算表达式
         * @return
         * @throws Exception
         */
        public boolean calculate(String pattern,String log) throws Exception {
            Stack<String> stack = new Stack<String>();
            ArrayList<String> tokens = generateReversePolish(getTokens(pattern));
            for (String token :tokens) {
                //如果是操作数则入栈
                if (!operatorMap.containsKey(token.toLowerCase())){
                    stack.push(token);
                }
                else{
                    String right = getValueFromContext(stack.pop(),log);
                    String left = getValueFromContext(stack.pop(), log);
                    stack.push(operate(left, right, token).toString());
                }
            }
            if (stack.size() == 1){
                String valueString = stack.pop();
                if (valueString.equalsIgnoreCase("true")){
                    return true;
                }
            }
            return false;
        }
     
        private String getValueFromContext(String variable, String log) {
            if (!variable.contains("$")){
                return variable;
            }else {
                if (variable.equalsIgnoreCase("$")){
                    return log;
                }else if (variable.contains("$.")){
                    //使用jsonpath解析
                    return  String.valueOf(JSONPath.read(log, variable));
                }
            }
            return null;
        }
     
     
        private ArrayList<String> generateReversePolish(ArrayList<String> tokens) throws Exception{
            //运算符stack, 和 操作数stack
            Stack<String> operatorStack = new Stack<String>();
            Stack<String> numberStack = new Stack<String>();
            for (String token : tokens) {
                //如果是操作数,直接插入到操作数stack
                if (!operatorMap.containsKey(token.toLowerCase())){
                    numberStack.push(token);
                }
                else{
                    if (operatorStack.empty()){
                        operatorStack.push(token);
                    }
                    else{
                        //如果是右括号 则要找到左括号 并且一次入栈到 操作数栈
                        if (token.equals(")")){
                            String popToken = null;
                            try {
                                while( !(popToken = operatorStack.pop()).equals("(") ){
                                    numberStack.push(popToken);
                                }
                                continue;
                            } catch (EmptyStackException e) {
                                throw new Exception("invalid expression:  '", e);
                            }
                        }
                        String preOperator = operatorStack.peek();
                        //如果之前的操作符是( ,则不用比较优先级 当前操作符直接入栈
                        if (preOperator.equals("(")){
                            operatorStack.push(token);
                        }
                        //比较操作符优先级, 如果该操作符优先级大于等于 , 则直接入栈
                        else if (operatorMap.get(token) <= operatorMap.get(preOperator)){
                            operatorStack.push(token);
                        }
                        //如果该操作符优先级 小于, 则在将该操作符如栈之前 要把栈顶操作符 弹出 插入 操作数栈
                        else{
                            numberStack.push( operatorStack.pop());
                            operatorStack.push(token);
                        }
     
                    }
     
                }
            }
            while (!operatorStack.empty()) {
                numberStack.push( operatorStack.pop());
            }
            ArrayList<String> resArrayList = new ArrayList<String>();
            String[] array = numberStack.toArray(new String[]{});
            for (int i = 0; i < array.length; i++) {
                resArrayList.add(array[i]);
            }
            return resArrayList;
        }
        private Boolean operate(String left,String right,String op){
            Op operator = Op.getByOperator(op);
            if (operator == null){
                System.out.println("未知的操作 op = "+op);
                return false;
            }
            Double leftNum =null;
            Double rightNum = null;
            switch (operator) {
                case GT:
                     leftNum = Double.valueOf(left);
                     rightNum = Double.valueOf(right);
                    return leftNum>rightNum;
                case GE:
                     leftNum = Double.valueOf(left);
                     rightNum = Double.valueOf(right);
                    return leftNum>=rightNum;
                case LT:
                     leftNum = Double.valueOf(left);
                     rightNum = Double.valueOf(right);
                    return leftNum<rightNum;
                case LE:
                     leftNum = Double.valueOf(left);
                     rightNum = Double.valueOf(right);
                    return leftNum<=rightNum;
                case EQ:
                    return left.equals(right);
                case AND:
                    if (!left.equals("true")){
                        return false;
                    }
                    if (!right.equals("true")){
                        return false;
                    }
                    return true;
                case OR:
                    if (left.equals("true")){
                        return true;
                    }
                    if (right.equals("true")){
                        return true;
                    }
                    return false;
                case CONTAINS:
                    if (left==null || right==null){
                        return false;
                    }
                    return left.contains(right);
                case CONTAINS_NOT:
                    if (left==null || right==null){
                        return false;
                    }
                    return !left.contains(right);
                default:return false;
            }
        }
     
        public static void main(String[] args) throws Exception {
            Parser parser = new Parser();
            //System.out.println(parser.calculate("$ contains zhangsan","name=zhangsan"));
            //System.out.println(parser.calculate("( $.name == zhangsan ) and ( $.age > 12 )","{\"name\":\"zhangsan\",\"age\":14}"));
            System.out.println(parser.calculate("( $.name CONTAINSNOT zhangsan ) and ( $.age > 12 )","{\"name\":\"zhangsaan1\",\"age\":14}"));
            System.out.println(parser.calculate("( $.name == zhangsan ) and ( $.age >= 12 )","{\"name\":\"zhangsan\",\"age\":12}"));
            System.out.println(parser.calculate("( $.name == zhangsan ) and ( $.age >= 12 )","{\"name\":\"zhangsan\",\"age\":11}"));
        }
    }
     
     



    参考:
    https://juejin.im/post/5b9bb590e51d450e7579cf0d
    https://gitee.com/wangzhuoa/ExpressionParser
    pom依赖

    <dependency>
        <groupId>com.google.guava</groupId>
        <artifactId>guava</artifactId>
        <version>29.0-jre</version>
    </dependency>
    <dependency>
        <groupId>com.jayway.jsonpath</groupId>
        <artifactId>json-path</artifactId>
        <version>2.4.0</version>
    </dependency>
     
    这里json解析使用到了jsonpath


    ————————————————
    版权声明:本文为CSDN博主「老黄瓜001」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/qq_33894426/article/details/107640591

  • 相关阅读:
    Django路由系统
    修改数据库时区问题
    Django框架篇
    前端css
    前端html
    前端初识
    数据库3
    数据库2
    数据库1
    数据库初识
  • 原文地址:https://www.cnblogs.com/LcxSummer/p/16241433.html
Copyright © 2020-2023  润新知