翻译逻辑表达式

  自定义逻辑表达式,关键字:= 等于,& 与,| 或, !非, ( , ) ,<> 包含,>< 不包含, # 不等于。

  表达式支持括号标识作用域。

  自动机分析如下:

   JAVA 实现:

public class ConditionAnalysis2 {
    //  终止符号
    Set<Character> signSet;

    ConditionAnalysis2() {
        this.signSet = new HashSet<Character>();
        signSet.add(' ');
        signSet.add('=');
        signSet.add('(');
        signSet.add(')');
        signSet.add('#');
        signSet.add('<');
        signSet.add('>');
        signSet.add('&');
        signSet.add('|');
    }public boolean analysis(String expression) {
        if (null == expression || expression.length() == 0) return false;
        if (expression.charAt(0) != '(') expression = "(" + expression + ")";
        Res res = this.getRes(expression, 0, new Context(ContextStatus.START), false);
        return res.res;
    }

    private Res getRes(String expression, int left, Context context, boolean isOppo) {
        int len = expression.length(), right = left;
        while (right < len) {
            char c = expression.charAt(right);
            if (c == ' ') {
                right++;
                continue;
            }
            // 回归
            if (')' == c) {
                if (isOppo) context.currentRes = !context.currentRes;
                Res res = new Res(context.currentRes, left, right + 1);
                System.out.println(expression.substring(isOppo ? left - 2 : left - 1, right + 1) + " : " + res.res);
                return res;
            }
            // 递归
            if (c == '(' || (c == '!' && right + 1 < len && expression.charAt(right + 1) == '(')) {
                Res partRes = null;
                if (c == '(') partRes = this.getRes(expression, right + 1, new Context(ContextStatus.WAIT_RES), false);
                else partRes = this.getRes(expression, right + 2, new Context(ContextStatus.WAIT_RES), true);
                if (null == partRes) throw new RuntimeException("error at " + right);
                if (null == context.currentRes) context.currentRes = partRes.res;
                else {
                    if (context.contextStatus == ContextStatus.AND) {
                        context.currentRes = context.currentRes & partRes.res;
                    } else if (context.contextStatus == ContextStatus.OR) {
                        context.currentRes = context.currentRes | partRes.res;
                    }
                }
                context.contextStatus = ContextStatus.RES;
                right = partRes.right;
                continue;
            }
            // 顺序
            if (c == '&') {
                context.contextStatus = ContextStatus.AND;
                right++;
                continue;
            }
            if (c == '|') {
                context.contextStatus = ContextStatus.OR;
                right++;
                continue;
            }
            Res partRes = this.getPartRes(expression, right);
            if (context.contextStatus == ContextStatus.WAIT_RES) {
                context.currentRes = partRes.res;
            } else if (context.contextStatus == ContextStatus.AND) {
                context.currentRes = context.currentRes & partRes.res;
            } else if (context.contextStatus == ContextStatus.OR) {
                context.currentRes = context.currentRes | partRes.res;
            }
            context.contextStatus = ContextStatus.RES;
            right = partRes.right;
        }
        if (isOppo) context.currentRes = !context.currentRes;
        return new Res(context.currentRes, left, right);
    }

    private Res getPartRes(String expression, int left) {
        int len = expression.length(), right = left;
        Context currentContext = new Context(ContextStatus.WAIT_TOKEN);
        Token leftToken = null;
        boolean isOppo = false;
        Res res = null;
        while (right < len) {
            char c = expression.charAt(right);
            if (c == ' ') {
                right++;
                continue;
            }
            if (c == '!') {
                if (currentContext.contextStatus == ContextStatus.WAIT_TOKEN || currentContext.contextStatus == ContextStatus.WAIT_OPPO2) {
                    currentContext.contextStatus = ContextStatus.WAIT_OPPO2;
                    isOppo = !isOppo;
                    right++;
                    continue;
                }
                throw new RuntimeException("error ! at " + right);
            }
            if (c == '=' || c == '#' || c == '<' || c == '>') {
                if (c == '=') currentContext.contextStatus = ContextStatus.EQ;
                else if (c == '#') currentContext.contextStatus = ContextStatus.NOT_EQ;
                else if (c == '<' && currentContext.contextStatus == ContextStatus.TOKEN)
                    currentContext.contextStatus = ContextStatus.XYW;
                else if (c == '<' && currentContext.contextStatus == ContextStatus.DYW)
                    currentContext.contextStatus = ContextStatus.NOT_CON;
                else if (c == '>' && currentContext.contextStatus == ContextStatus.TOKEN)
                    currentContext.contextStatus = ContextStatus.DYW;
                else if (c == '>' && currentContext.contextStatus == ContextStatus.XYW)
                    currentContext.contextStatus = ContextStatus.CON;
                right++;
                continue;
            }
            Token token = this.getToken(expression, right);
            if (currentContext.contextStatus == ContextStatus.WAIT_TOKEN || currentContext.contextStatus == ContextStatus.WAIT_OPPO2) {
                leftToken = token;
                currentContext.contextStatus = ContextStatus.TOKEN;
                right = token.right;
                continue;
            } else {
                Boolean currentRes = null;
                if (currentContext.contextStatus == ContextStatus.EQ) {
                    currentRes = token.token.equals(leftToken.token);
                } else if (currentContext.contextStatus == ContextStatus.NOT_EQ) {
                    currentRes = !token.token.equals(leftToken.token);
                } else if (currentContext.contextStatus == ContextStatus.CON) {
                    currentRes = leftToken.token.contains(token.token);
                } else if (currentContext.contextStatus == ContextStatus.NOT_CON) {
                    currentRes = !leftToken.token.contains(token.token);
                } else if (currentContext.contextStatus == ContextStatus.XYW) {
                    currentRes = Long.valueOf(leftToken.token) < Long.valueOf(token.token);
                } else if (currentContext.contextStatus == ContextStatus.DYW) {
                    currentRes = Long.valueOf(leftToken.token) > Long.valueOf(token.token);
                }
                if (null == currentRes) throw new RuntimeException("res is null! error at " + right);
                right = token.right;
                if (isOppo) currentRes = !currentRes;
                res = new Res(currentRes, left, right);
                break;
            }
        }
        System.out.println("   " + expression.substring(left, right) + " : " + res.res);
        return res;
    }

    private Token getToken(String expression, int left) {
        int len = expression.length(), right = left;
        char c = expression.charAt(right);
        StringBuilder stringBuilder = new StringBuilder();
        while (right < len && !this.signSet.contains(c)) {
            stringBuilder.append(expression.charAt(right));
            right++;
            if (right < len) c = expression.charAt(right);
        }
        return new Token(stringBuilder.toString(), left, right);
    }

    class Res {
        Boolean res;
        int left, right;

        public Res(Boolean res, int left, int right) {
            this.res = res;
            this.left = left;
            this.right = right;
        }
    }

    class Token {
        String token;
        int left;
        int right;

        Token(String token, int left, int right) {
            this.token = token;
            this.left = left;
            this.right = right;
        }
    }

    class Context {
        ContextStatus contextStatus;
        Boolean currentRes;

        Context(ContextStatus contextStatus) {
            this.contextStatus = contextStatus;
        }
    }

    public enum ContextStatus {
        // 外层状态
        START,
        WAIT_OPPO, WAIT_OPPO2,
        WAIT_RES, WAIT_RES2,
        RES,
        AND, OR,
        DONE,
        // 内层状态
        WAIT_TOKEN,
        TOKEN,
        EQ, NOT_EQ, XYW, DYW,
        CON, NOT_CON
    }
}

   JS实现:

function ConditionAnalysis() {
    this.termSet = new Set();
    this.termSet.add('=');
    this.termSet.add('(');
    this.termSet.add(')');
    this.termSet.add('#');
    this.termSet.add('>');
    this.termSet.add('<');
    this.termSet.add('&');
    this.termSet.add('|');

    this.analysis = function (expression) {
        if (!expression || expression.length == 0) return false;
        if (expression.charAt(0) != "(") expression = "(" + expression + ")";
        return this.getRes(expression, 0, "START", false);
    }

    this.getRes = function (expression, left, currentStatus, isOppo) {
        let len = expression.length, right = left, currentRes = null;
        while (right < len) {
            let c = expression.charAt(right);
            if (c == " ") {
                right++;
                continue;
            }
            if (c == ")") {
                if (currentRes === null) throw "currentRes is null! " + left + "," + right;
                if (isOppo) currentRes = !currentRes;
                console.log(expression.substring(isOppo ? left - 2 : left - 1, right + 1) + " : " + currentRes);
                return {data: currentRes, left, right};
            }
            if (c == "&") {
                if (currentStatus == "RES") {
                    currentStatus = "AND";
                    right++;
                    continue;
                }
                throw "error & at " + right;
            }
            if (c == "|") {
                if (currentStatus == "RES") {
                    currentStatus = "OR";
                    right++;
                    continue;
                }
                throw "error | at " + right;
            }
            if (c == "(" || (c == "!" && right + 1 < len && expression.charAt(right + 1) == "(")) {
                let partRes = this.getRes(expression, c == "!" ? right + 2 : right + 1, "WAIT_RES", c == "!" ? true : false);
                if (currentStatus == "START" || currentStatus == "WAIT_RES") currentRes = partRes.data;
                else if (currentStatus == "AND") currentRes = currentRes && partRes.data;
                else if (currentStatus == "OR") currentRes = currentRes || partRes.data;
                else throw "error at " + right + " , " + currentStatus;
                currentStatus = "RES";
                right = partRes.right + 1;
                continue;
            }
            let partRes = this.getPartRes(expression, right, "WAIT_TOKEN");
            if (currentStatus == "WAIT_RES") currentRes = partRes.data;
            else if (currentStatus == "AND") currentRes = currentRes && partRes.data;
            else if (currentStatus == "OR") currentRes = currentRes || partRes.data;
            else throw "error at " + right;
            currentStatus = "RES";
            right = partRes.right;
        }
        return {data: currentRes, left, right};
    }

    this.getPartRes = function (expression, left, currentStatus) {
        let len = expression.length, right = left, isOppo = false, leftToken = null;
        let res = null;
        while (right < len) {
            let c = expression.charAt(right);
            if (c == " " || c == "!" || c == "=" || c == "#" || c == "<" || c == ">") {
                if (c == "!") {
                    if (currentStatus == "WAIT_TOKEN" || currentStatus == "WAIT_OPPO") {
                        currentStatus = "WAIT_OPPO";
                        isOppo = !isOppo;
                    }
                } else if (c == "=") {
                    if (currentStatus != "TOKEN") throw "error = at " + right;
                    currentStatus = "EQ";
                } else if (c == "#") {
                    if (currentStatus != "TOKEN") throw "error = at " + right;
                    currentStatus = "NOT_EQ";
                } else if (c == "<") {
                    if (currentStatus == "TOKEN") currentStatus = "XYW";
                    else if (currentStatus == "DYW") currentStatus = "NOT_CON";
                    else throw "error < at " + right;
                } else if (c == ">") {
                    if (currentStatus == "XYW") currentStatus = "CON";
                    else if (currentStatus == "TOKEN") currentStatus = "DYW";
                    else throw "error > at " + right;
                }
                right++;
                continue;
            }
            let token = this.getToken(expression, right);
            right = token.right;
            if (currentStatus == "WAIT_TOKEN" || currentStatus == "WAIT_OPPO") {
                leftToken = token;
                currentStatus = "TOKEN";
            } else if (currentStatus == "EQ") {
                res = leftToken.data == token.data;
                break;
            } else if (currentStatus == "NOT_EQ") {
                res = leftToken.data != token.data;
                break;
            } else if (currentStatus == "XYW") {
                res = leftToken.data < token.data;
                break;
            } else if (currentStatus == "DYW") {
                res = leftToken.data > token.data;
                break;
            } else if (currentStatus == "CON") {
                let currRes = false, array = this.strToArray(leftToken.data);
                for (let j = 0; j < array.length; j++) {
                    if (array[j] == token.data) {
                        currRes = true;
                        break;
                    }
                }
                res = currRes;
                break;
            } else if (currentStatus == "NOT_CON") {
                let currRes = true, array = this.strToArray(leftToken.data);
                for (let j = 0; j < array.length; j++) {
                    if (array[j] == token.data) {
                        currRes = false;
                        break;
                    }
                }
                res = currRes;
                break;
            }
        }
        if (res == null) throw "getPartRes error: " + left + "," + right + ":" + expression.substring(left.right);
        if (isOppo) res = !res;
        console.log("  " + expression.substring(left, right) + " : " + res);
        return {data: res, left, right}
    }

    this.getToken = function (expression, left) {
        let len = expression.length, right = left, c = expression.charAt(right);
        let data = "";
        while (right < len && !this.termSet.has(c)) {
            data += c;
            right++;
            if (right < len) c = expression.charAt(right);
        }
        return {data, left, right};
    }

    this.strToArray = function (str) {
        if (!str || str.length == 0) return [];
        if (str.charAt(0) == "[") str = str.substring(1, str.length - 1);
        let array = str.split(",");
        return array;
    }
}


/*
     测试样例
     * 1=1 true
     * !1=1 false
     * 1=2 false
     * !1=2 true
     * 1>2 false
     * 1<2 true
     * [1,2,3,4,5]<>6 true
     * [1,2,3,4,5]><6 false
     * [1,2,3,4,5]<>1 false
     * [1,2,3,4,5]><1 true
     * 1#1 false
     * 1#3 true
     * 1=1&1=2 false
     * 1=1&2=2 true
     * 1=1|1=2 true
     * 1=3|1=2 false
     * 1=1&(1=2|1#1) false
     * !1=1&(1=2|1#1) false
     * !(1=1&(1=2|1#1)) true
     * 1=1&(1=2|1=1) true
     * (( 1 = 1 & ( 2 = 1 | 2 = 6))&[1,2,3,4,5]><5) false
     * ((1=2&(2=2|2=6))&[1,2,3,4,5]><5) false
     * (((1=1)|(1=2))&2=1|1=1) true
     * (((1=1)|(1=2))&(2=1&1=1)) false
     * !(((1=1)|(1=2))&(2=1&1=1)) true
     * (((1=1)|(1=2))&!(2=1&1=1)) true
 */
let expression = "((1=2&(2=2|2=6))&[1,2,3,4,5]><5)";
let analysis = new ConditionAnalysis();
let res = analysis.analysis(expression);
console.log(res);

 

posted @ 2023-02-27 22:58  牛有肉  阅读(55)  评论(0编辑  收藏  举报