Antlr4实现表达式解析

最近做数据清洗打算做一个表达式解析模块希望能支持嵌套的模块,类似于nifi的recordpath模块,例:

上下文数据:{"name": "zs","age":18}

表达式:replace(/name,replace(/name,zs,s),replace(/age,8,replace(/age,1,22228888)))

预期结果:z1222288888

最初直接引入nifi的recordpath模块调用发现可以使用,但是引入了非常多nifi的基础类,与项目结合度比较低,并且数据类型要多一层转换(映射成nifi定义的基础类型执行后再映射回来),遂看了下nifi的实现方式,是使用的Antlr3,网上查了下Antlr3的资料非常的少,发现大部分资料都是使用的Antlr4,在网上找到好多计算器的例子,参考着搞了好几天,走了不少弯路,最后发现实际上非常简单,g4文件只有5行就可以,Antlr4真的非常强大,下面是g4及Visitor代码:

Govern.g4

grammar Govern;

expr:	expr'('expr (','expr)*')'       # func
    |   COL                             # col
    |	ELEMENT                         # element
    ;

ELEMENT : [A-Za-z0-9]+ ;      // 匹配数字及字母
COL : '/'[A-Za-z0-9]+ ;       // 匹配列名
Visitor实现,由于目前只是做一个demo,所以只做了replace方法的实现所以硬编码了replace方法,replace方法只调用了string的replace方法,固不贴代码了,可以根据需要拓展更多方法
public class DoFuncGovernVisitor extends GovernBaseVisitor<Object> {

    private Map<String, Object> context;

    @Override
    public Object visitFunc(GovernParser.FuncContext ctx) {
        List<Object> exprList = new ArrayList<>();
        for (GovernParser.ExprContext exprContext : ctx.expr()) {
            exprList.add(exprContext.accept(this));
        }
        return getFunc(exprList.get(0).toString()).doFunc(exprList.stream().skip(1).toArray());
    }

    @Override
    public Object visitElement(GovernParser.ElementContext ctx) {
        return ctx.getText();
    }

    @Override
    public Object visitCol(GovernParser.ColContext ctx) {
        return context.get(ctx.getText().substring(1));
    }

    private Func<?> getFunc(String funcName) {
        System.out.println(funcName);
        return new Replace();
    }

    public void setContext(Map<String, Object> context) {
        this.context = context;
    }
}

main测试

public static void main(String[] args) {
        String query = "replace(name,replace(name,zs,s),replace(age,8,replace(age,1,22228888)))";

        GovernLexer lexer = new GovernLexer(CharStreams.fromString(query));
        GovernParser parser = new GovernParser(new CommonTokenStream(lexer));
        DoFuncGovernVisitor visitor = new DoFuncGovernVisitor();

        Map<String, Object> column = new HashMap<>();
        column.put("name", "zs");
        column.put("age", 18);

        visitor.setContext(column);

        System.out.println(visitor.visit(parser.expr()));
    }

执行结果

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值