# listGenerate **Repository Path**: MIEAPP/listGenerate ## Basic Information - **Project Name**: listGenerate - **Description**: 集合生成 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-07-25 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 判断一个数是否在指定的集合内是很简单的,只需要将集合存入java的`List`或`Set`(根据集合的特性`Set`更适合)类型中,使用他的`contains`方法即可判断,但是很多时候集合并不固定,我们需要把他写到配置文件中去,这个时候该怎么办呢? >比如: > 1. 有一个集合是`1`到`100`的整数 > 2. 有一个集合是`1`到`100`的偶数 > 3. 有一个集合是`1`到`100`的偶数并且不要`50`到`60`之间的偶数 > 4. 有一个集合是`1`到`100`的偶数并且里面的数也是`3`的倍数 上面的两个问题我们应该怎么解决呢?怎么写到配置文件中呢? 最简单的方法当然是之间枚举所有的数出来(但是这样太不优雅了,数值过大就不太好配置了) 为了解决上面的问题,一个比较好的方式就是开发DSL了,使用antlr让开发更加简单 贴代码了: ```antlr # ^ 用来表示集合的交集运算 # + 用来表示集合的与运算(可以省略) # - 用来表示集合的差运算 # {} 改变( '^' > '+' = '-' )之间的运算优先级 # [ 代表 包含start # ( 代表 不包含start # ] 代表 包含end # ) 代表 不包含end # speed 代表步长,如果前面加个%代表求余为零的数 grammar Test; range : range op='^' range #Assoc | range op=('+'|'-') range #AddSub | range range #Add | '{' range '}' #Simple | ('['|'(') start ',' speed ',' end (')'|']') #SSE | ('['|'(') start ',' end (')'|']') #SE | ('['|'(') start (')'|']') #S ; start : INT; speed : '%'? INT; end : INT; SMALLBRACKETLEFT : '('; SMALLBRACKETRIGHT : ')'; MEDIUMBRACKETLEFT : '['; MEDIUMBRACKETRIGHT : ']'; ADDOPTION : '+'; SUBOPTION : '-'; INT : [0-9]+; NL : '\r'?'\n'; WS : [ \t\r\n]+ -> skip; ``` 编写visitor: ``` package cn.infomany.test0; import java.util.HashSet; import java.util.Set; import java.util.stream.Collectors; /** * @description: 范围访问器 * @author: zhanjinbing * @data: 2020-03-03 15:17 */ public class RangesVisitor extends TestBaseVisitor { @Override public Object visitAdd(TestParser.AddContext ctx) { Set result = new HashSet<>(); Set result0 = (Set) visit(ctx.range(0)); Set result1 = (Set) visit(ctx.range(1)); result.addAll(result0); result.addAll(result1); return result; } @Override public Object visitSE(TestParser.SEContext ctx) { int speed = 1; int start = (int) visit(ctx.start()); int end = (int) visit(ctx.end()); return visitSSE(start, speed, end, ctx.start.getType() == TestLexer.MEDIUMBRACKETLEFT, ctx.stop.getType() == TestLexer.MEDIUMBRACKETRIGHT); } private Set visitSSE(int start, int speed, int end, boolean hasStart, boolean hasEnd) { Set result = new HashSet<>(); for (int i = start; i < end; i += speed) { result.add(i); } if (!hasStart) { result.remove(start); } if (hasEnd) { result.add(end); } return result; } @Override public Object visitSimple(TestParser.SimpleContext ctx) { return visit(ctx.range()); } @Override public Object visitS(TestParser.SContext ctx) { Set results = new HashSet<>(); if (ctx.start.getType() == TestLexer.SMALLBRACKETLEFT || ctx.stop.getType() == TestLexer.SMALLBRACKETRIGHT) { return results; } results.add((Integer) visit(ctx.start())); return results; } @Override public Object visitSSE(TestParser.SSEContext ctx) { Object speedObj = visit(ctx.speed()); int start = (int) visit(ctx.start()); int end = (int) visit(ctx.end()); Set results; if (speedObj instanceof String) { results = visitSSE(start, 1, end, ctx.start.getType() == TestLexer.MEDIUMBRACKETLEFT, ctx.stop.getType() == TestLexer.MEDIUMBRACKETRIGHT); final Integer tmpInt = Integer.valueOf(((String) speedObj).substring(1)); results = results.stream().filter(it -> it % tmpInt == 0).collect(Collectors.toSet()); } else if (speedObj instanceof Integer) { results = visitSSE(start, (Integer) speedObj, end, ctx.start.getType() == TestLexer.MEDIUMBRACKETLEFT, ctx.stop.getType() == TestLexer.MEDIUMBRACKETRIGHT); } else { throw new RuntimeException("[speed]格式有误"); } return results; } @Override public Object visitAddSub(TestParser.AddSubContext ctx) { Set result = new HashSet<>(); Set result0 = (Set) visit(ctx.range(0)); Set result1 = (Set) visit(ctx.range(1)); result.addAll(result0); if (ctx.op.getType() == TestLexer.ADDOPTION) { result.addAll(result1); } else { result.removeAll(result1); } return result; } @Override public Object visitAssoc(TestParser.AssocContext ctx) { Set result = new HashSet<>(); Set result0 = (Set) visit(ctx.range(0)); Set result1 = (Set) visit(ctx.range(1)); result0.stream().forEach(it -> { if (result1.contains(it)) { result.add(it); } }); return result; } @Override public Object visitStart(TestParser.StartContext ctx) { return Integer.valueOf(ctx.INT().getText()); } @Override public Object visitSpeed(TestParser.SpeedContext ctx) { // 检查是不是单纯的int String reg = "\\d+"; if (ctx.getText().matches(reg)) { return Integer.valueOf(ctx.INT().getText()); } return ctx.getText(); } @Override public Object visitEnd(TestParser.EndContext ctx) { return Integer.valueOf(ctx.INT().getText()); } } ``` 主类: ``` package cn.infomany.test0; import org.antlr.v4.runtime.CharStream; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.tree.ParseTree; import java.util.ArrayList; /** * @description: 测试主程序 * @author: zhanjinbing * @data: 2020-03-03 15:11 */ public class TestMain { public static void main(String[] args) throws Exception { // 新建一个CharStreams,从标准输入读取数据 CharStream input = CharStreams.fromStream(System.in); // 新建一个词法符号的缓冲区,用于存储词法分析器将生成的词法符号 TestLexer lexer = new TestLexer(input); // 新建一个词法符号的缓冲区,用于存储词法分析器将生成的词法符号 CommonTokenStream tokens = new CommonTokenStream(lexer); // 新建一个语法分析器,处理词法符号缓冲区中的内容 TestParser parser = new TestParser(tokens); // 针对init规则,开始语法分析 ParseTree tree = parser.range(); RangesVisitor rangesVisitor = new RangesVisitor(); Object visit = rangesVisitor.visit(tree); System.out.println("visit = " + visit); } } ``` 问题一: ![](https://upload-images.jianshu.io/upload_images/7473008-5535043c0fb9032f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 问题二: ![](https://upload-images.jianshu.io/upload_images/7473008-c6a04fc754adbaae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 问题三: ![](https://upload-images.jianshu.io/upload_images/7473008-f471a6d79a81c5b0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 问题四: ![](https://upload-images.jianshu.io/upload_images/7473008-cc44a862bd6cfa1d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) 数组是乱序的,因为使用的Set来保存的 [引用文章请表明出处](https://www.jianshu.com/p/bf3dc8ce12ec)