前言
最近在寻觅搜索查询中可以对查询语句进行解析的一个工具,然后偶然就发现了这个ANTLR4 (语法用到了正则,有多个语言的支持,你常用的很多SQL的解析都用到他了)。当然语法解析我是一窍不通的,本篇只是简单的通过一个demo来说下简单的使用。官方示例
简单的回顾下正则
因为ANTLR4语法用到了正则
- | 表示或(多个可以匹配的条件)
-
- 匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 *
- ? 配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 ?。
-
- 匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 +。
- ~ 表示取反
- 范围运算符:.. 或者 -,比如小写字母的表示:'a'..'z' 或者 [a-z]
工具的简单使用
1.IDEA中安装插件

2.简单的分析个查询解析的demo
- 1.查询单词
- 2.-是排除特定的单词
- 3.site:是限定某个范围
- 4.复杂点的可能就看不懂了,因为各种变量定义到处都是的只不过不妨碍入门(工具嘛先会拿来用
txt
//必填项
//文件名为SearchQuery.g4
grammar SearchQuery;
//注意下面定义了很多变量声明
//其实就是定义别名数据、然后使用
//必填项
// 整个查询语句由多个 term 构成 (term为空格隔开的单词)
searchQuery
: searchTerm* EOF
;
//匹配的查询内容 必须项
//这里意思每个term可以是site开头的限定域;
//也可以是-开头的排除数据
//每个term是一个单词
searchTerm
: SITE_INCLUDE
| SITE_EXCLUDE
| WORD
;
// 匹配包含 site: 但不以 - 开头的项 => 表示包含
//site: 开头后接一个或多个字母、数字、点、冒号、斜杠、减号或下划线的字符串,用于识别类似网站地址的标记。
SITE_INCLUDE
: 'site:' [a-zA-Z0-9.:/\-_]+
;
// 匹配 -site: 开头的项 => 表示排除
SITE_EXCLUDE
: '-'[a-zA-Z0-9.:/\-_]+
;
// 普通词
//因为ANTLR4 不支持\S 所以写成了下面的这种方式
WORD
: ~[ \t\r\n]+
;
// 空格忽略
WS
: [ \t\r\n]+ -> skip
;
3.用安装的插件(ANTLR4)可以进行查看语法树和对写的文件进行一个验证

4.用安装的ANTLR4插件可以进行代码生成
- 需要填些生成文件的路径和报名
5.实现自己的逻辑
-
这里生成代码例子是我在网上找的两个个计算器的例子。生成的代码文件名都是固定的
-
生成代码后,我们还需要要实现自己的逻辑处理(继承后实现自己的逻辑,生成的是默认)
-
((下面图片右边的东西,可以不指定(就是我们写的变量名)也可以前面是表达式后面用#指定
-
重写的方法就是上图右侧的四个方法
typescript
public class MyCalculatorVisitor extends CalculatorBaseVisitor<Object> {
@Override
public Object visitParenExpr(CalculatorParser.ParenExprContext ctx) {
return visit(ctx.expr());
}
@Override
public Object visitMultOrDiv(CalculatorParser.MultOrDivContext ctx) {
Object obj0 = ctx.expr(0).accept(this);
Object obj1 = ctx.expr(1).accept(this);
if ("*".equals(ctx.getChild(1).getText())) {
return (Float) obj0 * (Float) obj1;
} else if ("/".equals(ctx.getChild(1).getText())) {
return (Float) obj0 / (Float) obj1;
}
return 0f;
}
@Override
public Object visitAddOrSubstract(CalculatorParser.AddOrSubstractContext ctx) {
Object obj0 = ctx.expr(0).accept(this);
Object obj1 = ctx.expr(1).accept(this);
if ("+".equals(ctx.getChild(1).getText())) {
return (Float) obj0 + (Float) obj1;
} else if ("-".equals(ctx.getChild(1).getText())) {
return (Float) obj0 - (Float) obj1;
}
return 0f;
}
@Override
public Object visitFloat(CalculatorParser.FloatContext ctx) {
return Float.parseFloat(ctx.getText());
}
}
public static void main(String[] args) {
String query = "3.1 * (6.3 - 4.51) + 5 * 4";
//创建一个词法分析器,用于将输入转换为标记
CalculatorLexer lexer = new CalculatorLexer(new ANTLRInputStream(query));
// 创建一个解析器,用于将标记转换为AST
CalculatorParser parser = new CalculatorParser(new CommonTokenStream(lexer));
// 创建一个AST遍历器,用于计算表达式的值
CalculatorVisitor visitor = new MyCalculatorVisitor();
System.out.println(visitor.visit(parser.expr())); // 25.549
}