接上面
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>
@Test
public 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);
}
//更新新的分组ID
rule.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);
// 从字符流分析词法, 解析为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());
//设置自定义变量为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的ObjectMapper
ObjectMapper 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;
}
}