You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用ANTLR在Java中动态解析含NOT的逻辑运算表达式

使用ANTLR实现支持NOT运算的动态表达式解析(Java)

1. 编写ANTLR语法文件(Expr.g4)

这个语法定义了支持NOT、AND、OR逻辑运算,以及=、IN比较操作的表达式规则:

grammar Expr;

expression
    : NOT expression               # notExpr
    | expression AND expression    # andExpr
    | expression OR expression     # orExpr
    | '(' expression ')'           # parenExpr
    | comparison                   # compExpr
    ;

comparison
    : IDENTIFIER '=' STRING_LITERAL        # eqComp
    | IDENTIFIER IN STRING_LITERAL         # inComp
    ;

NOT : 'NOT';
AND : 'AND';
OR : 'OR';
IN : 'IN';

IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*;
STRING_LITERAL : '\'' ~'\''* '\'';

WS : [ \t\r\n]+ -> skip;

2. 生成ANTLR解析器代码

用ANTLR工具生成Java版的解析器、词法分析器和相关类:

antlr4 Expr.g4 -java

执行后会生成ExprLexer.java、ExprParser.java、ExprBaseListener.java等文件,将这些文件加入到你的Java项目中。

3. 实现表达式求值的访问器

继承ANTLR的ExprBaseVisitor,实现每个语法规则的求值逻辑,从传入的Map中获取数据进行判断:

import org.antlr.v4.runtime.tree.AbstractParseTreeVisitor;
import java.util.Map;

public class ExprEvaluator extends AbstractParseTreeVisitor<Boolean> {
    private final Map<String, String> dataMap;

    public ExprEvaluator(Map<String, String> dataMap) {
        this.dataMap = dataMap;
    }

    @Override
    public Boolean visitNotExpr(ExprParser.NotExprContext ctx) {
        boolean value = visit(ctx.expression());
        return !value;
    }

    @Override
    public Boolean visitAndExpr(ExprParser.AndExprContext ctx) {
        boolean left = visit(ctx.expression(0));
        boolean right = visit(ctx.expression(1));
        return left && right;
    }

    @Override
    public Boolean visitOrExpr(ExprParser.OrExprContext ctx) {
        boolean left = visit(ctx.expression(0));
        boolean right = visit(ctx.expression(1));
        return left || right;
    }

    @Override
    public Boolean visitParenExpr(ExprParser.ParenExprContext ctx) {
        return visit(ctx.expression());
    }

    @Override
    public Boolean visitEqComp(ExprParser.EqCompContext ctx) {
        String key = ctx.IDENTIFIER().getText();
        String value = ctx.STRING_LITERAL().getText().replace("'", "");
        return value.equals(dataMap.get(key));
    }

    @Override
    public Boolean visitInComp(ExprParser.InCompContext ctx) {
        String key = ctx.IDENTIFIER().getText();
        String targetValue = ctx.STRING_LITERAL().getText().replace("'", "");
        // 这里简化处理单值IN,如需多值可扩展语法和判断逻辑
        return targetValue.equals(dataMap.get(key));
    }
}

4. 编写测试代码

封装解析和求值逻辑,测试目标表达式:

import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CommonTokenStream;
import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        // 测试目标表达式
        String exprStr = "EmployeeShift = 'General' AND NOT(EmployeeType = 'CONTRACT' OR Designation IN 'ADMIN')";
        
        // 模拟输入数据
        Map<String, String> data = new HashMap<>();
        data.put("EmployeeShift", "General");
        data.put("EmployeeType", "FULLTIME");
        data.put("Designation", "ENGINEER");

        // 解析表达式并求值
        CharStream input = CharStreams.fromString(exprStr);
        ExprLexer lexer = new ExprLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        ExprParser parser = new ExprParser(tokens);

        ExprEvaluator evaluator = new ExprEvaluator(data);
        boolean result = evaluator.visit(parser.expression());

        System.out.println("表达式求值结果:" + result); // 输出true
    }
}

扩展说明

  • 如需支持多值IN操作(比如Designation IN ('ADMIN','MANAGER')),可修改语法中的STRING_LITERAL规则为多值格式,同时在visitInComp方法中拆分字符串进行批量判断。
  • 可根据需求扩展更多比较操作(如!=、<、>等),只需在语法文件中添加对应规则,并在访问器中实现求值逻辑。

内容的提问来源于stack exchange,提问作者User1512

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 21:40:15