JAVA动态表达式:Antlr4 G4 模板 + 读取字符串表达式结构树

安装antlr4插件

创建一个后缀是g4的文件

grammar Expr;

expression :
             '(' expression ')'          # parens
            | expression 'and' expression # andOp
            | expression 'or' expression  # orOp
            | '@' VARNAME comparison_op NUMBER # comparison
            | '@' VARNAME comparison_op STRING # comparison
            | '@' NUMBER comparison_op NUMBER # comparison
            | '@' STRING comparison_op STRING # comparison
            | '@' VARNAME comparison_op VARNAME # comparison
            | '@' VARNAME contains_op VARNAME # comparison
            | '@' VARNAME contains_op NUMBER # comparison
            | '@' VARNAME contains_op STRING # comparison
            | '@' STRING contains_op STRING # comparison
            |  VARNAME comparison_op NUMBER # comparison
            |  VARNAME comparison_op STRING # comparison
            |  NUMBER comparison_op NUMBER # comparison
            |  STRING comparison_op STRING # comparison
            |  VARNAME comparison_op VARNAME # comparison
            |  VARNAME contains_op VARNAME # comparison
            |  VARNAME contains_op NUMBER # comparison
            |  VARNAME contains_op STRING # comparison
            |  STRING contains_op STRING # comparison
            ;

comparison_op : '<' | '<=' | '>' | '>=' | '==' | '!=';
contains_op: 'contains' | 'notcontains';

STRING : '\'' ( '\\' . | '\\\'' | ~[\\'] )* '\'';
NUMBER : '-'? [0-9]+ ('.' [0-9]+)?;
VARNAME : [a-zA-Z_][a-zA-Z_0-9]*;
WS : [ \t\r\n]+ -> skip; // 忽略空白字符
fragment Letter: [a-zA-Z];
fragment Digit: [0-9];
fragment ChineseCharacter: [\u4e00-\u9fa5];

上面的文件可以直接解析如下格式的表达式:

@prices == 1 and (@val >=1 or @name<=4) and 1==1 and '2'=='3' and '1123' contains '1' and '23455' notcontains '5'

右键生成代码

 引入POM

 <!--动态表达式-->
        <dependency>
            <groupId>org.antlr</groupId>
            <artifactId>antlr4</artifactId>
            <version>4.10.1</version>
        </dependency>

 测试表达式结构

 @Test
    public  void  Test00(){
        // 构建字符流
        CodePointCharStream charStream = CharStreams.fromString("@prices == 1 and (@val >=1 or @name<=4) and 1==1 and '2'=='3' and '1123' contains '1' and '23455' notcontains '5'");

        // 从字符流分析词法, 解析为token
        ExprLexer lexer = new ExprLexer(charStream);

        // 从token进行分析
        ExprParser parser = new ExprParser(new CommonTokenStream( lexer) );

        // 使用监听器,遍历语法树,根据语法定义,prog为语法树的根节点
        ParseTree prog = parser.expression();

        // 创建监听器
        CustomerExprListener listener = new CustomerExprListener();


        // 遍历AST并使用监听器处理
        ParseTreeWalker walker = new ParseTreeWalker();
        walker.walk(listener, prog);

        // 打印生成的语法树
        //System.out.println( prog.toStringTree(parser));

    }

拿到表达式以后,就可以把结果处理成实际业务想要的对象了

package com.java.core.web.antlr4;

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.tree.ErrorNode;
import org.antlr.v4.runtime.tree.TerminalNode;

public class CustomerExprListener  extends ExprBaseListener{
    @Override
    public void enterEveryRule(ParserRuleContext ctx) {
        //System.out.println("Entering rule: " + ctx.getText());
    }

    @Override
    public void exitEveryRule(ParserRuleContext ctx) {
        //System.out.println("Exiting rule: " + ctx.getText());
    }

    @Override
    public void visitTerminal(TerminalNode node) {
        System.out.println("Visiting terminal: " + node.getText());
    }

    @Override
    public void visitErrorNode(ErrorNode node) {
        //System.out.println("Visiting error: " + node.getText());
    }
}

监听输出的内容


Visiting terminal: @
Visiting terminal: prices
Visiting terminal: ==
Visiting terminal: 1
Visiting terminal: and
Visiting terminal: (
Visiting terminal: @
Visiting terminal: val
Visiting terminal: >=
Visiting terminal: 1
Visiting terminal: or
Visiting terminal: @
Visiting terminal: name
Visiting terminal: <=
Visiting terminal: 4
Visiting terminal: )
Visiting terminal: and
Visiting terminal: 1
Visiting terminal: ==
Visiting terminal: 1
Visiting terminal: and
Visiting terminal: '2'
Visiting terminal: ==
Visiting terminal: '3'
Visiting terminal: and
Visiting terminal: '1123'
Visiting terminal: contains
Visiting terminal: '1'
Visiting terminal: and
Visiting terminal: '23455'
Visiting terminal: notcontains
Visiting terminal: '5'

可以把监控的类提取出来

/**
     * 遍历语法树节点
     * @param tree
     */
    public static RuleTest traverseTree(ParseTree tree, String name, RuleTest ruleTest) {
        //自定义变量
        // public String type; //类型 1-属性 2-值 (由比较操作符决定)
        // public String group; //组 0-不用添加组 1-需要添加组 (由连续小括号的数量决定,如果两个符号连续都是小括号,那么系统会认为是一个组)
        // public String bracket;//括号 判断是否是组 (小括号的数量记录)
        // public String isObject;//是否new object (条件对象 0-不创建 1-创建 由逻辑运算符决定 如 and/or)

        if (tree instanceof TerminalNode) {
            TerminalNode terminalNode = (TerminalNode) tree;
            //得到树节点
            String text = terminalNode.getText();
            //获取条件组
            List<Condition> list = ruleTest.getConditionList();
            //判断节点类型 (比较操作符/逻辑运算符号/小括号/中括号/@符)
            int res = CheckSymbolOptions.getNameOrValue(text);
            if (res == 1){ //比较操作符
                ruleTest.setType("2");
                ruleTest.setEndBracket("0");
                if (ruleTest.getGroup() == null || ruleTest.getGroup().equals("0")){
                    if (list.size()>0){
                        Condition condition = list.get(list.size()-1);
                        String symbolOptions = SymbolOptions.getNameOrValue(text);
                        condition.setCompareOperation(symbolOptions);//比较操作(操作符)
                    }
                }else{
                    Condition cond = list.get(list.size()-1);
                    List<Condition> conditionList = cond.getConditionList();
                    if (conditionList.size()>0){
                        Condition condition = conditionList.get(conditionList.size()-1);
                        String symbolOptions = SymbolOptions.getNameOrValue(text);
                        condition.setCompareOperation(symbolOptions);//比较操作(操作符)
                    }
                }

            }else if (res ==2){ //逻辑运算符
                if (ruleTest.getGroup() == null || ruleTest.getGroup().equals("0")){
                    //添加条件对象
                    Condition condition = addCondition(name,"symbol",text);
                    list.add(condition);
                    ruleTest.setIsObject("1");//需要添加条件对象  0-不添加 1-添加
                }else{
                    Condition cond = list.get(list.size()-1);
                    List<Condition> conditionList = cond.getConditionList();
                    //添加条件对象
                    Condition condition = addCondition(name,"symbol",text);
                    conditionList.add(condition);
                    ruleTest.setIsObject("1");//需要添加条件对象  0-不添加 1-添加
                }
            }else if (res==3){ //括号标识符
                if (text.equals("(")){
                    ruleTest.setType("1");
                    if (ruleTest.getBracket()==null || ruleTest.getBracket().equals("0")){
                        ruleTest.setBracket("1");
                    }else{
                        int va = Integer.valueOf(ruleTest.getBracket())+1;
                        ruleTest.setBracket(String.valueOf(va));
                        if (va==2){
                            if (list== null){
                                list = new ArrayList<>();
                            }
                            ruleTest.setGroup("1");
//                            if (list.size()==0){
//                                Condition condition = addCondition(name,"group",null);
//                                int endva = Integer.valueOf(ruleTest.getSubscript())+1;
//                                ruleTest.setSubscript(String.valueOf(endva));//记录下标
//                                condition.setTierIndex(String.valueOf(endva));
//                                list.add(condition);
//                                ruleTest.setConditionList(list);
//                            }
                            //创建对象
                            Condition condition = addCondition(name,"group",null);
                            condition.setDescribe(null);
                            int endva = Integer.valueOf(ruleTest.getSubscript())+1;
                            ruleTest.setSubscript(String.valueOf(endva));//记录下标
                            condition.setTierIndex(String.valueOf(endva));
                            list.add(condition);
                            ruleTest.setConditionList(list);
                            ruleTest.setIsObject("0");//添加对象后回复初始状态
                        }
                        ruleTest.setBracket("0");
                    }
                    if (ruleTest.getId()==null){
                        //设置rule属性
                        ruleTest.setId(generateId("rule"));//id需要自动生成 rule_xxxxxxxxxx(10位数)
                        ruleTest.setName(name);
                        ruleTest.setSubscript("1");//记录索引
                        ruleTest.setTierIndex("1");//层级索引 需要确定来源
                    }
                }
                if (text.equals(")")){
                    if (ruleTest.getEndBracket()==null || ruleTest.getEndBracket().equals("0")){
                        ruleTest.setEndBracket("1");
                    }else{
                        int endva = Integer.valueOf(ruleTest.getEndBracket())+1;
                        ruleTest.setEndBracket(String.valueOf(endva));
                    }
                    if (ruleTest.getEndBracket().equals("2")){
                        ruleTest.setGroup("0");
                    }
                }
            }else if (res ==4){ //@ 参数标识
                ruleTest.setType("1");
            }else {
                //初始化对象与集合
                if (list== null || list.size()==0){
                    list = new ArrayList<>();
                    Condition condition = addCondition(name,"single",null);
                    list.add(condition);
                    ruleTest.setConditionList(list);
                }
                if (ruleTest.getGroup() == null || ruleTest.getGroup().equals("0")){
                    if (ruleTest.getIsObject()!=null){
                        if (ruleTest.getIsObject().equals("1")){
                            //创建对象
//                            Condition condition = new Condition();
                            Condition condition = addCondition(name,"single",null);
                            list.add(condition);
                            ruleTest.setIsObject("0");//添加对象后回复初始状态
                        }
                    }
                }else{
                    if (ruleTest.getIsObject()!=null){
                        if (ruleTest.getIsObject().equals("1")) {
                            Condition cond = list.get(list.size()-1);
                            List<Condition> conditionList = cond.getConditionList();
                            //创建对象
                            Condition addCondition = addCondition(name,"single",null);
                            conditionList.add(addCondition);
                            ruleTest.setIsObject("0");//添加对象后回复初始状态
                        }
                    }
                }
                if (list.size()>0){
                    if (ruleTest.getGroup()== null || ruleTest.getGroup().equals("0") ){
                        //获取属性详情,判断属性是否存在,如果存在拿到属性名称、类型等信息
                        String type = DataType.getDataType("5000"); //此处需要替换
                        Condition condition = list.get(list.size()-1);
                        if (condition.getLeftOperatorExpression()==null || condition.getRightOperatorExpression()==null ){
                            if (ruleTest.getType().equals("1")){
                                //创建左边运算符表达式
                                LeftOperatorExpression left = addLeftOperatorExpression(type,text);
                                condition.setLeftOperatorExpression(left);
                                ruleTest.setType("0");
                            }
                            if (ruleTest.getType().equals("2")){
                                //创建右边运算符表达式
                                RightOperatorExpression right = addRightOperatorExpression(type,text);
                                condition.setRightOperatorExpression(right);
                                ruleTest.setType("0");
                                ruleTest.setBracket("0");
                            }
                        }
                    }else{
                        if (ruleTest.getGroup().equals("1")){
                            String type = DataType.getDataType("5000"); //此处需要替换
                            Condition cond = list.get(list.size()-1);
//                            Rule rule = cond.getRule();
                            List<Condition> conditionList = cond.getConditionList();
                            //初始化对象与集合
                            if (conditionList== null || conditionList.size()==0){
                                conditionList = new ArrayList<>();
                                Condition condition = addCondition(name,"single",null);
                                if (condition.getLeftOperatorExpression() == null || condition.getRightOperatorExpression() == null) {
                                    if (ruleTest.getType().equals("1")) {
                                        //创建左边运算符表达式
                                        LeftOperatorExpression left = addLeftOperatorExpression(type, text);
                                        condition.setLeftOperatorExpression(left);
                                        ruleTest.setType("0");
                                    }
                                    if (ruleTest.getType().equals("2")) {
                                        //创建右边运算符表达式
                                        RightOperatorExpression right = addRightOperatorExpression(type, text);
                                        condition.setRightOperatorExpression(right);
                                        ruleTest.setType("0");
                                        ruleTest.setBracket("0");
                                    }
                                }
                                conditionList.add(condition);
                                cond.setConditionList(conditionList);
                            }else{
                                Condition condition = conditionList.get(conditionList.size()-1);
                                if (condition.getLeftOperatorExpression() == null || condition.getRightOperatorExpression() == null) {
                                    if (ruleTest.getType().equals("1")) {
                                        //创建左边运算符表达式
                                        LeftOperatorExpression left = addLeftOperatorExpression(type, text);
                                        condition.setLeftOperatorExpression(left);
                                        ruleTest.setType("0");
                                    }
                                    if (ruleTest.getType().equals("2")) {
                                        //创建右边运算符表达式
                                        RightOperatorExpression right = addRightOperatorExpression(type, text);
                                        condition.setRightOperatorExpression(right);
                                        ruleTest.setType("0");
                                        ruleTest.setBracket("0");
                                    }
                                }
                            }

                        }

                    }
                }
            }
        }
        //递归 循环遍历
        for (int i = 0; i < tree.getChildCount(); i++) {
            traverseTree(tree.getChild(i),name,ruleTest);
        }
        return ruleTest;
    }

上面的g4模板,是把@prices这样的变量,分成了@+price,下面的g4模板是获得整体@price变量的

grammar Expr;

expression :
             '(' expression ')'          # parens
            | expression 'and' expression # andOp
            | expression 'or' expression  # orOp
            | AT_VARNAME comparison_op NUMBER # comparison
            | AT_VARNAME comparison_op STRING # comparison
            | AT_VARNAME comparison_op VARNAME # comparison
            | AT_VARNAME contains_op VARNAME # comparison
            | AT_VARNAME contains_op NUMBER # comparison
            | AT_VARNAME contains_op STRING # comparison
            | AT_VARNAME comparison_op AT_VARNAME # comparison
            | VARNAME comparison_op NUMBER # comparison
            | VARNAME comparison_op STRING # comparison
            | NUMBER comparison_op NUMBER # comparison
            | STRING comparison_op STRING # comparison
            | VARNAME comparison_op VARNAME # comparison
            | VARNAME contains_op VARNAME # comparison
            | VARNAME contains_op NUMBER # comparison
            | VARNAME contains_op STRING # comparison
            | STRING contains_op STRING # comparison
            ;

comparison_op : '<' | '<=' | '>' | '>=' | '==' | '!=';
contains_op: 'contains' | 'notcontains';

AT_VARNAME : '@' VARNAME;
STRING : '\'' ( '\\' . | '\\\'' | ~[\\'] )* '\'';
NUMBER : '-'? [0-9]+ ('.' [0-9]+)?;
VARNAME : [a-zA-Z_][a-zA-Z_0-9]*;
WS : [ \t\r\n]+ -> skip; // 忽略空白字符
fragment Letter: [a-zA-Z];
fragment Digit: [0-9];
fragment ChineseCharacter: [\u4e00-\u9fa5];

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值