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

ANTLR表达式中允许逗号等特殊字符的实现方案咨询

问题描述

我用ANTLR实现基于Map的动态表达式解析,参考现有方案完成基础功能后,新增了IN、STARTSWITH、ENDSWITH等条件。在实现IN功能时,计划用逗号分割字符串集合,但传入表达式时触发错误:

line 1:64 token recognition error at: ','

需要解决如何让表达式支持逗号等特殊字符,同时正确解析IN操作的集合参数。

当前使用的语法文件、EvalVisitor修改代码及测试表达式如下:

现有语法文件

grammar SimpleBoolean;

parse
 : expression EOF
 ;

expression
 : LPAREN expression RPAREN                       #parenExpression
 | NOT expression                                 #notExpression
 | left=expression op=comparator right=expression #comparatorExpression
 | left=expression op=binary right=expression     #binaryExpression
 | bool                                           #boolExpression
 | IDENTIFIER                                     #identifierExpression
 | DECIMAL                                        #decimalExpression
 ;

comparator
 : GT | GE | LT | LE | EQ | NE | IN | NOTIN | STARTSWITH | ENDSWITH | NULL | NOTNULL
 ;

binary
 : AND | OR
 ;

bool
 : TRUE | FALSE
 ;

AND        : 'AND' ;
OR         : 'OR' ;
NOT        : 'NOT';
TRUE       : 'TRUE' ;
FALSE      : 'FALSE' ;
GT         : '>' ;
GE         : '>=' ;
LT         : '<' ;
LE         : '<=' ;
EQ         : '=' ;
NE         : '!=' ;
IN         : 'IN' ;
NOTIN      : 'NOTIN' ;
STARTSWITH : 'STARTSWITH' ;
ENDSWITH   : 'ENDSWITH' ;
NULL       : 'NULL' ;
NOTNULL    : 'NOTNULL' ;
LPAREN     : '(' ;
RPAREN     : ')' ;
DECIMAL    : '-'? [0-9]+ ( '.' [0-9]+ )? ;
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
WS         : [ \r\t\u000C\n]+ -> skip;

修改后的EvalVisitor代码片段

if (ctx.op.EQ() != null) {
    return this.visit(ctx.left).equals(this.visit(ctx.right));
}
else if (ctx.op.IN() != null) {
    String checkVal[] = this.visit(ctx.right).toString().split(",");
    boolean valuePresent = false;
    
    for(String value : checkVal) {
        if(value.equals(this.visit(ctx.left).toString()))
            valuePresent = true;
    }
    return valuePresent;
}

测试表达式

ID = ID AND NOT ( comments = comments AND system IN system,admin,developer )

解决方案

1. 错误原因

当前语法未定义逗号作为合法Token,也未为IN/NOTIN操作设计专门的集合参数规则——IN操作的右侧应该是括号包裹的逗号分隔元素列表,而非普通表达式,原语法的comparatorExpression规则无法适配这种结构,导致解析器识别逗号时失败。

2. 修改语法文件

需要新增逗号Token,并为IN/NOTIN单独定义语法规则,调整expression的结构:

grammar SimpleBoolean;

parse
 : expression EOF
 ;

expression
 : LPAREN expression RPAREN                       #parenExpression
 | NOT expression                                 #notExpression
 | left=expression op=inComparator right=inList  #inExpression
 | left=expression op=comparator right=expression #comparatorExpression
 | left=expression op=binary right=expression     #binaryExpression
 | bool                                           #boolExpression
 | IDENTIFIER                                     #identifierExpression
 | DECIMAL                                        #decimalExpression
 ;

// 拆分IN/NOTIN到单独的比较器规则
inComparator
 : IN | NOTIN
 ;

// 普通比较器规则
comparator
 : GT | GE | LT | LE | EQ | NE | STARTSWITH | ENDSWITH | NULL | NOTNULL
 ;

// 定义IN操作的集合列表
inList
 : LPAREN (expression (',' expression)*)? RPAREN
 ;

binary
 : AND | OR
 ;

bool
 : TRUE | FALSE
 ;

AND        : 'AND' ;
OR         : 'OR' ;
NOT        : 'NOT';
TRUE       : 'TRUE' ;
FALSE      : 'FALSE' ;
GT         : '>' ;
GE         : '>=' ;
LT         : '<' ;
LE         : '<=' ;
EQ         : '=' ;
NE         : '!=' ;
IN         : 'IN' ;
NOTIN      : 'NOTIN' ;
STARTSWITH : 'STARTSWITH' ;
ENDSWITH   : 'ENDSWITH' ;
NULL       : 'NULL' ;
NOTNULL    : 'NOTNULL' ;
LPAREN     : '(' ;
RPAREN     : ')' ;
COMMA      : ',' ; // 新增逗号Token
DECIMAL    : '-'? [0-9]+ ( '.' [0-9]+ )? ;
IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
WS         : [ \r\t\u000C\n]+ -> skip;

3. 调整EvalVisitor逻辑

不再通过字符串分割处理集合,直接遍历解析后的inList元素:

// 新增inExpression的处理逻辑
@Override
public Boolean visitInExpression(SimpleBooleanParser.InExpressionContext ctx) {
    Object leftValue = visit(ctx.left);
    List<SimpleBooleanParser.ExpressionContext> elements = ctx.inList().expression();
    
    boolean isPresent = false;
    for (SimpleBooleanParser.ExpressionContext elemCtx : elements) {
        Object elemValue = visit(elemCtx);
        if (leftValue.equals(elemValue)) {
            isPresent = true;
            break;
        }
    }
    
    // 处理NOTIN的反向逻辑
    if (ctx.op.NOTIN() != null) {
        return !isPresent;
    }
    return isPresent;
}

4. 修正测试表达式

IN操作的集合必须用括号包裹,修正后的表达式:

ID = ID AND NOT ( comments = comments AND system IN (system,admin,developer) )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 00:23:11