如何用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
相关产品推荐
相关产品推荐

