接上面
JAVA动态表达式:Antlr4 G4 模板 + 读取字符串表达式结构树-CSDN博客
目前已经实现了常量及分组常规表达式的解析。
String formula = "'啦啦啦'=='1' and 1==1 and '2'=='3' and '1123' contains '1' and '23455' notcontains '5'";
String formula = "'啦啦啦'=='1' and (1==1 or 2==2) and '1123' contains '1' and '23455' notcontains '5'";
String formula = "'啦啦啦'=='1' and (1 contains 1 or 2 notcontains 2) ";
String formula = "(1==1 or 2==2) and '啦啦啦'=='1'";
String formula = "((1==1) or (2==2)) and '啦啦啦'=='1'";
String formula = "((1==1 and (2==2 or 3==3)) or (2==2 or 3==3)) and '啦啦啦'=='1'";
实现思路通过Antlr4把解析得到表达式树:
下面的RuleEntity rule对象,就是把上面的结构树给拿到了。
// 构建字符流
CodePointCharStream charStream = CharStreams.fromString(formula);
// 从字符流分析词法, 解析为token
ExprLexer lexer = new ExprLexer(charStream);
// 从token进行分析
ExprParser parser = new ExprParser(new CommonTokenStream(lexer));
// 使用监听器,遍历语法树,根据语法定义,prog为语法树的根节点
ParseTree progTree = parser.expression();if (((ExprParser.ExpressionContext) progTree).exception != null) {throw new Exception("输入的表达式不符合解析规则");
}
// 遍历语法树节点
RuleEntity rule = traverseTree(progTree, name, new RuleEntity());
这样通过循环你就能得到这串表达式的每个值:((1==1 and (2==2 or 3==3)) or (2==2 or 3==3)) and '啦啦啦'=='1'
比如,第一个是( ,第二个是(,第三个是1,第四个是==......
这样你就需要通过逻辑去拼接成这样的对象:
{"id":"rule_2o0S3Ar37K","name":"","tierIndex":"1","conditionList":[{"id":"HK3e6pbRh8","type":"group","tierIndex":"2","conditionList":[{"id":"GmaIWw94NU","type":"group","tierIndex":"3","conditionList":[{"id":"gqx7N9E8p6","type":"single","leftOperatorExpression":{"id":"Constant_ZE0K2xEU82","type":"1","valueType":"double","value":"1","label":"数字"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_35054671Wu","type":"1","valueType":"double","value":"1","label":"数字"},"describe":""},{"id":"MOsI066Zys","type":"symbol","formulaRelation":"and"},{"id":"R364030W6T","type":"group","tierIndex":"4","conditionList":[{"id":"KtCN58q1Qj","type":"single","leftOperatorExpression":{"id":"Constant_3v9x4vQ716","type":"1","valueType":"double","value":"2","label":"数字"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_20I9PuvuLE","type":"1","valueType":"double","value":"2","label":"数字"},"describe":""},{"id":"1JViMLz2L0","type":"symbol","formulaRelation":"or"},{"id":"5PQD6ZU2a2","type":"single","leftOperatorExpression":{"id":"Constant_K6626YX2ya","type":"1","valueType":"double","value":"3","label":"数字"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_27885U5143","type":"1","valueType":"double","value":"3","label":"数字"},"describe":""}]}]},{"id":"D5dnzS9162","type":"symbol","formulaRelation":"or"},{"id":"F15k4S12AZ","type":"group","tierIndex":"3","conditionList":[{"id":"gJS0jy1Kl7","type":"single","leftOperatorExpression":{"id":"Constant_Z5v3vD9ky6","type":"1","valueType":"double","value":"2","label":"数字"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_W6ZlHv110E","type":"1","valueType":"double","value":"2","label":"数字"},"describe":""},{"id":"K967v6PJ8E","type":"symbol","formulaRelation":"or"},{"id":"99L0cJj55g","type":"single","leftOperatorExpression":{"id":"Constant_8VM6MJlQ08","type":"1","valueType":"double","value":"3","label":"数字"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_4bKLn5xQsA","type":"1","valueType":"double","value":"3","label":"数字"},"describe":""}]}]},{"id":"685x2JL36x","type":"symbol","formulaRelation":"and"},{"id":"tt104S829A","type":"single","leftOperatorExpression":{"id":"Constant_52nUmF4dmO","type":"1","valueType":"string","value":"啦啦啦","label":"字符串"},"compareOperation":"1","rightOperatorExpression":{"id":"Constant_08q1K2KO6s","type":"1","valueType":"string","value":"1","label":"字符串"},"describe":""}]}
然后下面是用到的实现逻辑:
POM文件
<!--JSON--><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.2.3</version><classifier>jdk15</classifier></dependency><!--动态表达式--><dependency><groupId>org.antlr</groupId><artifactId>antlr4</artifactId><version>4.10.1</version></dependency>
@Testpublic void Test00() throws Exception {//String formula="@prices == 1 and (@val >=1 or @name<=4) and 1==1 and '2'=='3' and '1123' contains '1' and '23455' notcontains '5'";//这个逻辑暂时没开发//String formula = "'啦啦啦'=='1' and 1==1 and '2'=='3' and '1123' contains '1' and '23455' notcontains '5'";//String formula = "'啦啦啦'=='1' and (1==1 or 2==2) and '1123' contains '1' and '23455' notcontains '5'";//String formula = "'啦啦啦'=='1' and (1 contains 1 or 2 notcontains 2) ";//String formula = "(1==1 or 2==2) and '啦啦啦'=='1'";//String formula = "((1==1) or (2==2)) and '啦啦啦'=='1'";String formula = "((1==1 and (2==2 or 3==3)) or (2==2 or 3==3)) and '啦啦啦'=='1'";String json = FormulaToJson.formulaToJson("", formula);System.out.println(json);}
package com.java.core.web.antlr4.util;import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.java.core.web.antlr4.ExprLexer;
import com.java.core.web.antlr4.ExprParser;
import com.java.core.web.antlr4.param.AbnormalParameter;
import com.java.core.web.antlr4.param.DeletionParameter;
import com.java.core.web.antlr4.param.Parameter;
import com.java.core.web.antlr4.param.ParameterPojo;
import com.java.core.web.antlr4.pojo.*;
import org.antlr.v4.runtime.CharStreams;
import org.antlr.v4.runtime.CodePointCharStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;public class FormulaToJson {/*** 遍历语法树节点** @param tree*/public static RuleEntity traverseTree(ParseTree tree, String name, RuleEntity rule) {//自定义变量// public String type; //类型 1-属性 2-值 (由比较操作符决定)// public String group; //组 0-不用添加组 1-需要添加组 (有一个小括号)// public String bracket;//括号 判断是否是组 (小括号的数量记录)// public String isObject;//是否new object (条件对象 0-不创建 1-创建 由逻辑运算符决定 如 and/or)if (tree instanceof TerminalNode) {TerminalNode terminalNode = (TerminalNode) tree;//得到树节点String text = terminalNode.getText().replace("'", "");//获取条件组List<Condition> list = rule.getConditionList();//判断节点类型 (比较操作符/逻辑运算符号/小括号/中括号/@符)int res = CheckSymbolOptions.getNameOrValue(text);if (res == 1) { //比较操作符rule.setType("2");rule.setEndBracket("0");if (rule.getGroup() == null || rule.getGroup().equals("0")) {if (list.size() > 0) {Condition condition = list.get(list.size() - 1);String symbolOptions = SymbolOptions.getNameOrValue(text);condition.setCompareOperation(symbolOptions);//比较操作(操作符)}} else {//取当前分组的最后一条数据Condition condition = getLastGroupCondition(list, rule);;condition = condition.getConditionList().get(condition.getConditionList().size() - 1);String symbolOptions = SymbolOptions.getNameOrValue(text);condition.setCompareOperation(symbolOptions);//比较操作(操作符)}} else if (res == 2) { //逻辑运算符if (rule.getGroup() == null || rule.getGroup().equals("0")) {//添加条件对象Condition condition = addCondition(name, "symbol", text);list.add(condition);rule.setIsObject("1");//需要添加条件对象 0-不添加 1-添加rule.setType("1");} else {//获得当前组的对象Condition cond = getLastGroupCondition(list, rule);List<Condition> conditionList = cond.getConditionList();//添加条件对象Condition condition = addCondition(name, "symbol", text);conditionList.add(condition);rule.setIsObject("1");//需要添加条件对象 0-不添加 1-添加}} else if (res == 3) { //括号标识符if (text.equals("(")) {if (rule.getId() == null) {//设置rule属性rule.setId(generateId("rule"));//id需要自动生成 rule_xxxxxxxxxx(10位数)rule.setName(name);rule.setSubscript("1");//记录索引rule.setTierIndex("1");//层级索引 需要确定来源}rule.setType("1");if (rule.getBracket() == null || rule.getBracket().equals("0")) {rule.setBracket("1");}int va = Integer.valueOf(rule.getBracket()) + 1;rule.setBracket(String.valueOf(va));//创建对象Condition condition = addCondition(name, "group", null);rule.setGroup("1");if (rule.getGroupIds() == null || rule.getGroupIds().size() == 0) {rule.setGroupIds(new ArrayList<>());}condition.setDescribe(null);if (rule.getSubscript() == null) {rule.setSubscript("1");}int endva = Integer.valueOf(rule.getSubscript()) + 1;rule.setSubscript(String.valueOf(endva));//记录下标condition.setTierIndex(String.valueOf(endva));rule.setIsObject("0");//添加对象后回复初始状态if (list == null) {list = new ArrayList<>();list.add(condition);rule.setConditionList(list);} else if (rule.getGroupIds().size() == 0) {list.add(condition);} else {//保证每个分组都是最后一个Condition cond = getLastGroupCondition(list, rule);condition.setTierIndex(String.valueOf(Integer.valueOf(cond.getTierIndex()) + 1));if (cond.getConditionList() == null) {cond.setConditionList(new ArrayList<>());}cond.getConditionList().add(condition);}//更新新的分组IDrule.getGroupIds().add(condition.getId());rule.setBracket("0");}if (text.equals(")")) {//判断上一层是否是分组,如果不是分组则设置不是分组的标记if (rule.getGroupIds().size() > 0) {//现在使用的组rule.getGroupIds().remove(rule.getGroupIds().size() - 1);}if (rule.getGroupIds().size() == 0) {rule.setGroup("0");}}} else if (res == 4 || text.lastIndexOf("@") >= 0) { //@ 参数标识rule.setType("1");} else {//初始化对象与集合if (list == null || list.size() == 0) {list = new ArrayList<>();Condition condition = addCondition(name, "single", null);list.add(condition);rule.setConditionList(list);}if (rule.getGroup() == null || rule.getGroup().equals("0")) {if (rule.getIsObject() != null) {if (rule.getIsObject().equals("1")) {//创建对象Condition condition = addCondition(name, "single", null);list.add(condition);rule.setIsObject("0");//添加对象后回复初始状态}}} else {if (rule.getIsObject() != null && rule.getIsObject().equals("1")) {Condition cond = getLastGroupCondition(list, rule);List<Condition> conditionList = cond.getConditionList();//创建对象Condition addCondition = addCondition(name, "single", null);conditionList.add(addCondition);rule.setIsObject("0");//添加对象后回复初始状态rule.setType("1");//添加左边值}}Condition condition = null;if (rule.getGroup() != null && rule.getGroup().equals("1")) {condition = getLastGroupCondition(list, rule);//获取最后的分组对象List<Condition> conditionList = condition.getConditionList();Condition cond = null;//初始化对象与集合if (conditionList == null || conditionList.size() == 0) {conditionList = new ArrayList<>();cond = addCondition(name, "single", null);setCondition(cond, text, rule);conditionList.add(cond);condition.setConditionList(conditionList);} else {cond = conditionList.get(conditionList.size() - 1);setCondition(cond, text, rule);}} else {condition = list.get(list.size() - 1);setCondition(condition, text, rule);}}}//递归 循环遍历for (int i = 0; i < tree.getChildCount(); i++) {traverseTree(tree.getChild(i), name, rule);}return rule;}//获取最后一个分组对象private static Condition getLastGroupCondition(List<Condition> list, RuleEntity rule) {String groupId = rule.groupIds.get(rule.groupIds.size() - 1);Condition cond = list.get(list.size() - 1);while (true) {if (cond.getId().equals(groupId)) {break;}cond = cond.getConditionList().get(cond.getConditionList().size() - 1);}return cond;}private static void setCondition(Condition condition, String text, RuleEntity rule) {//获取属性详情,判断属性是否存在,如果存在拿到属性名称、类型等信息String type = DataType.getDataType(text);if (condition.getLeftOperatorExpression() == null || condition.getRightOperatorExpression() == null) {if (rule.getType() == null || rule.getType().equals("1")) {//创建左边运算符表达式LeftOperatorExpression left = addLeftOperatorExpression(type, text);condition.setLeftOperatorExpression(left);rule.setType("0");}if (rule.getType().equals("2")) {//创建右边运算符表达式RightOperatorExpression right = addRightOperatorExpression(type, text);condition.setRightOperatorExpression(right);rule.setType("0");rule.setBracket("0");}//如果都是常量,则进行类型对齐//一边是日期,一边是非日期,则全部改成字符串//一边是数字,一边非数字,则全部改成字符串//或者状态是contains和notcontains(7,8)也需要转成字符串if (condition.getLeftOperatorExpression() != null&& condition.getLeftOperatorExpression().getId().lastIndexOf("Constant") >= 0&& condition.getRightOperatorExpression() != null&& condition.getRightOperatorExpression().getId().lastIndexOf("Constant") >= 0&& (!condition.getLeftOperatorExpression().getValueType().equals(condition.getRightOperatorExpression().getValueType())|| condition.getCompareOperation().equals("7") || condition.getCompareOperation().equals("8"))) {condition.getLeftOperatorExpression().setValueType("string");condition.getLeftOperatorExpression().setLabel(SymbolOptions.getNameOrValue("string"));condition.getRightOperatorExpression().setValueType("string");condition.getRightOperatorExpression().setLabel(SymbolOptions.getNameOrValue("string"));}}}/*** 创建 Condition 对象** @param name* @param type* @return*/public static Condition addCondition(String name, String type, String text) {//创建对象Condition condition = new Condition();//设置条件组属性condition.setFormulaRelation(text);condition.setId(generateId(""));//id需要自动生成 bc3369691d(10位数)condition.setType(type);//类型(单个的 如何获取??)if (text == null) {condition.setDescribe(name);//描述}if (type.equals("group")) {condition.setDescribe("");}return condition;}/*** 创建左边运算符表达式** @param type* @param text* @return*/public static LeftOperatorExpression addLeftOperatorExpression(String type, String text) {LeftOperatorExpression left = new LeftOperatorExpression();if (text.lastIndexOf("@") >= 0) {left.setId(generateId("Parameter"));//id需要自动生成 Parameter_xxxxxxxxxx(10位数)//是变量left.setType("6");left.setValue(text);//值} else {left.setId(generateId("Constant"));//id需要自动生成 Parameter_xxxxxxxxxx(10位数)//是常量left.setType("1");left.setValue(text);//值}left.setValueType(type);//值类型left.setLabel(SymbolOptions.getNameOrValue(type));//参数名称(属性值的名称 @ 如何定义?没有依据)return left;}/*** 创建右边运算符表达式** @param type* @param text* @return*/public static RightOperatorExpression addRightOperatorExpression(String type, String text) {RightOperatorExpression right = new RightOperatorExpression();if (text.lastIndexOf("@") >= 0) {right.setId(generateId("Parameter"));//id需要自动生成 Parameter_xxxxxxxxxx(10位数)//是变量right.setType("6");right.setValue(text);//值} else {right.setId(generateId("Constant"));//id需要自动生成 Parameter_xxxxxxxxxx(10位数)//是常量right.setType("1");right.setValue(text);//值}right.setValueType(type);//值类型right.setLabel(SymbolOptions.getNameOrValue(type));//参数名称(属性值的名称 @ 如何定义?没有依据)return right;}/*** 将公式转换成json** @param name 公式名称* @param formula 公式* @return*/public static String formulaToJson(String name, String formula) throws Exception {// 构建字符流CodePointCharStream charStream = CharStreams.fromString(formula);// 从字符流分析词法, 解析为tokenExprLexer lexer = new ExprLexer(charStream);// 从token进行分析ExprParser parser = new ExprParser(new CommonTokenStream(lexer));// 使用监听器,遍历语法树,根据语法定义,prog为语法树的根节点ParseTree progTree = parser.expression();if (((ExprParser.ExpressionContext) progTree).exception != null) {throw new Exception("输入的表达式不符合解析规则");}// 遍历语法树节点RuleEntity rule = traverseTree(progTree, name, new RuleEntity());//设置自定义变量为null,做转换json忽略空置预处理if (rule != null) {rule.setType(null);rule.setIsObject(null);rule.setGroup(null);rule.setGroupIds(null);rule.setBracket(null);rule.setEndBracket(null);rule.setSubscript(null);}// 初始化Jackson的ObjectMapperObjectMapper objectMapper = new ObjectMapper();objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); // 忽略空值字段// 将对象转换为JSON字符串String json = null;try {json = objectMapper.writeValueAsString(rule);} catch (JsonProcessingException e) {throw new RuntimeException(e);}return json;}/*** 数字和字母随机组合10位数** @param name* @return*/public static String generateId(String name) {String generate = "";Random random = new Random();for (int i = 0; i < 10; i++) {// 输出字母还是数字String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";// 字符串if ("char".equalsIgnoreCase(charOrNum)) {// 取得大写字母还是小写字母int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;generate += (char) (choice + random.nextInt(26));} else if ("num".equalsIgnoreCase(charOrNum)) { // 数字generate += String.valueOf(random.nextInt(10));}}if (name == null || "".equals(name)) {return generate;}return name + "_" + generate;}/*** 根据属性ID 获取表单属性集合** @param parameterId* @return*/public static List<Parameter> getParameterById(Long parameterId) {//定义属性集合List<Parameter> parameterList = new ArrayList<>();if (parameterId != null) {//属性查询操作//获取属性值String jsonString = "{\"list\":[],\"config\":{\"layout\":\"horizontal\",\"labelCol\":{\"xs\":4,\"sm\":4,\"md\":4,\"lg\":4,\"xl\":4,\"xxl\":4},\"wrapperCol\":{\"xs\":18,\"sm\":18,\"md\":18,\"lg\":18,\"xl\":18,\"xxl\":18},\"view\":[{\"viewMode\":1,\"viewName\":\"发起视图\",\"controlList\":[]},{\"viewMode\":2,\"viewName\":\"审批视图\",\"controlList\":[]},{\"viewMode\":3,\"viewName\":\"查看视图\",\"controlList\":[]},{\"viewMode\":4,\"viewName\":\"打印视图\",\"controlList\":[]}],\"parameter\":[{\"name\":\"金额\",\"code\":\"Price\",\"describe\":\"结算金额\",\"value\":\"5000\",\"type\":\"string\",\"id\":\"793565f5314254944cdf1d79b2e20df6\"},{\"name\":\"数字\",\"code\":\"Price\",\"describe\":\"1\",\"value\":\"1\",\"type\":\"double\",\"id\":\"fea23b17d0d4f44de96cc0f01ce63abf\"}],\"cache\":false,\"hideRequiredMark\":false,\"hiddenFieldStrategy\":1,\"formStyle\":1,\"formStyleWidth\":\"95%\",\"formStyleBgColor\":\"#ecf2f7\",\"formStyleBg\":\"\",\"formHead\":\"\",\"formStyleTitle\":\"Test_Xiangfei\",\"formTitleStatus\":false,\"formSystemStyleId\":2,\"isShowHeader\":true,\"isFold\":false,\"isShowBoxIcon\":true,\"formStyleTitleCss\":{\"align\":\"center\",\"fontSize\":18,\"color\":\"#0c1b74\"},\"event\":{\"init\":null},\"eventList\":[],\"opinionExtra\":true}}";//通过fromObject将json字符串翻译成JSON对象(JSONObject)JSONObject jsonObject = JSONObject.parseObject(jsonString);//获取JSONObject对象值String config = jsonObject.getString("config");//结果就是简单的值类型if (config.length() > 0) {//二次转换将json对象值翻译成JSON对象JSONObject jsonConfig = JSONObject.parseObject(config);//获取JSONObject对象值String parameter = jsonConfig.getString("parameter");if (parameter.length() > 0) {//将对象属性转换成属性集合parameterList = JsonUtil.jsonToList(parameter, Parameter.class);}}}return parameterList;}//判断属性是否存在public static ParameterPojo checkParameter(String param, List<Parameter> list) {ParameterPojo parameterPojo = new ParameterPojo();//定义属性Code集合List<String> codeList = new ArrayList<>();if (list.size() > 0) {for (Parameter par : list) {if (par != null) {codeList.add(par.getCode());}}}//判断属性int res = Collections.frequency(codeList, param);if (res == 1) {//存在属性Parameter parameter = new Parameter();for (Parameter par : list) {if (par.getCode().equals(param)) {}}parameter.setCode(param);parameterPojo.setParameter(parameter);} else if (res > 1) {//一对多属性 需要抛异常AbnormalParameter abnormalParameter = new AbnormalParameter();abnormalParameter.setCode(param);parameterPojo.setAbnormalParameter(abnormalParameter);} else {//缺失属性DeletionParameter deletionParameter = new DeletionParameter();deletionParameter.setCode(param);parameterPojo.setDeletionParameter(deletionParameter);}return parameterPojo;}}