提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
条件拼接 - 根据入参生成where条件
- 前言
- 一、GraphConditionEnum 支持的条件
- 二、ConditionServiceImpl 实现类
- 三、DbDataTypeEnum 入参的数据类型
- 四、GraphTypeEnum 图数据的类型
- 五、工具类 & 静态参数类
- 总结
前言
最近做了这个功能,根据不同的入参生产where条件。
值得一记,虽然有很多业务上的枚举,但是大体上思路没问题,就是拆解起来稍微麻烦点。偷懒了…随手记录下吧。
入参示例:
[
{
"rootName": "std_people",
"fieldName": "name",
"dbDataType":1,
"option": "contain",
"value": ["李"]
},{
"rootName": "",
"fieldName": "",
"dbDataType":null,
"option": "or",
"value": []
},{
"rootName": "std_people",
"fieldName": "age",
"dbDataType":3,
"option": "betweenEnd",
"value": [16,60]
}
]
一、GraphConditionEnum 支持的条件
import org.apache.commons.lang3.StringUtils;
/**
* @author lobster.long
*/
public enum GraphConditionEnum {
/**
* 条件
*/
GREATER_THAN("greaterThan", ">", " %s > %s "),
LESS_THAN("lessThan", "<", " %s < %s "),
EQUAL("equal", "=", " %s = %s "),
GREATER_EQUAL("greaterEqual", ">=", " %s >= %s "),
LESS_EQUAL("lessEqual", "<=", " %s <= %s "),
CONTAIN("contain", "CONTAINS", " %s CONTAINS %s "),
NOT_EMPTY("notEmpty", "IS NOT NULL", " %s IS NOT NULL "),
IS_EMPTY("isEmpty", "IS NULL", " %s IS NULL "),
NOT_BETWEEN_END("notBetweenEnd", "", " (%s < %s OR %s > %s) "),
BETWEEN_END("betweenEnd", "", " (%s >= %s and %s <= %s) "),
START("start", "", " %s STARTS WITH %s "),
END("end", "", " %s ENDS WITH %s "),
BOTH_CONTAIN("bothContain", "", " %s CONTAINS '%s' "),
NOT_BOTH_CONTAIN("notBothContain", "", " NOT %s CONTAINS '%s' "),
NOT_CONTAIN("notContain", "", " NOT %s CONTAINS %s "),
NOT_START("notStart", "", " NOT %s STARTS WITH %s "),
NOT_END("notEnd", "", " NOT %s END WITH %s "),
OR("or", "", " OR "),
AND("and", "", " AND "),
NO_EQUAL("noEqual", "", " %s <> %s "),
MANY_VALUE_CONTAIN("manyValueContain", "", " %s IN [%s] "),
LEFT_CONTAIN("leftContain", "", " %s STARTS WITH %s "),
RIGHT_CONTAIN("rightContain", "", " %s END WITH %s "),
FULL_EQUAL("full_equal", "", " %s = %s "),
;
GraphConditionEnum(String sourceCondition, String targetCondition, String targetConditionFormat) {
this.sourceCondition = sourceCondition;
this.targetCondition = targetCondition;
this.targetConditionFormat = targetConditionFormat;
}
private String sourceCondition;
private String targetCondition;
private String targetConditionFormat;
public String getSourceCondition() {
return sourceCondition;
}
public void setSourceCondition(String sourceCondition) {
this.sourceCondition = sourceCondition;
}
public String getTargetCondition() {
return targetCondition;
}
public void setTargetCondition(String targetCondition) {
this.targetCondition = targetCondition;
}
public String getTargetConditionFormat() {
return targetConditionFormat;
}
public void setTargetConditionFormat(String targetConditionFormat) {
this.targetConditionFormat = targetConditionFormat;
}
public static GraphConditionEnum getEnumBySourceCondition(String sourceCondition) {
for (GraphConditionEnum conditionEnum : GraphConditionEnum.values()) {
if (conditionEnum.getSourceCondition().equalsIgnoreCase(sourceCondition)) {
return conditionEnum;
}
}
return null;
}
public static String getConditionFormat(String sourceCondition) {
if(StringUtils.isBlank(sourceCondition)){
return null;
}
for (GraphConditionEnum conditionEnum : GraphConditionEnum.values()) {
if (conditionEnum.getSourceCondition().equals(sourceCondition)) {
return conditionEnum.getTargetConditionFormat();
}
}
return null;
}
}
二、ConditionServiceImpl 实现类
里面有些逻辑是业务上的,但是不涉及公司具体业务
iimport com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.protobuf.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Service
public class ConditionServiceImpl {
/**
* 构建查询条件
*
* @param conditions 帮我填条件
* @return 构建查询条件
* @throws Exception 找不到操作符合规则
*/
public String buildCondition(List<AutoReqConditionDto> conditions) throws Exception {
//非空检查-无条件
StringBuilder fullConditionStr = new StringBuilder();
if (CollectionUtils.isEmpty(conditions)) {
return fullConditionStr.toString();
}
//有条件
Map<String, String> shortStdNames = new HashMap<>();
StringBuilder tempConditionStr = new StringBuilder();
//循环解析\拼接每一个条件
for (AutoReqConditionDto condition : conditions) {
GraphConditionEnum graphConditionEnum = GraphConditionEnum.getEnumBySourceCondition(condition.getOption());
if (Objects.isNull(graphConditionEnum)) {
throw new Exception("条件: " + condition.getOption() + " 找不到对应规则");
}
//特殊处理OR AND
if (GraphConditionEnum.OR == graphConditionEnum) {
tempConditionStr.append(GraphConditionEnum.OR.name());
continue;
} else if (GraphConditionEnum.AND == graphConditionEnum) {
if (tempConditionStr.toString().contains(GraphConditionEnum.OR.name())) {
tempConditionStr = new StringBuilder(StringConstant.LEFT_LITTLE_BRACKET + tempConditionStr + StringConstant.RIGHT_LITTLE_BRACKET);
}
fullConditionStr.append(tempConditionStr).append(GraphConditionEnum.AND.name());
tempConditionStr = new StringBuilder();
continue;
} else if (StringUtils.isNotEmpty(tempConditionStr)) {
String cypherAfterOr = RegexUtils.getCypherAfterRegex(tempConditionStr.toString(), GraphConditionEnum.OR.name());
if (StringUtils.isNotEmpty(cypherAfterOr)) {
fullConditionStr.append(StringConstant.LEFT_LITTLE_BRACKET).append(tempConditionStr).append(StringConstant.RIGHT_LITTLE_BRACKET).append(GraphConditionEnum.AND.name());
tempConditionStr = new StringBuilder();
}
}
//找到主体
String rootName = condition.getRootName();
if (!shortStdNames.containsKey(rootName)) {
String shotStdName = RegexUtils.getCypherAfterRegex(rootName, StringConstant.UNDERLINE);
shortStdNames.put(rootName, shotStdName);
}
//拼接条件 根据不同option组装不同的
try {
String conditionStr = buildConditionFormat(shortStdNames, condition, graphConditionEnum);
tempConditionStr.append(conditionStr);
} catch (Exception e) {
log.error("condition转条件format异常:{},{}", JSONObject.toJSONString(condition), e.getMessage());
throw new Exception("条件值转数字异常");
}
}
if (tempConditionStr.toString().contains(GraphConditionEnum.OR.name())) {
tempConditionStr = new StringBuilder(StringConstant.LEFT_LITTLE_BRACKET + tempConditionStr + StringConstant.RIGHT_LITTLE_BRACKET);
}
fullConditionStr.append(tempConditionStr);
return StringConstant.WHERE + fullConditionStr;
}
/**
* 构造条件
*
* @param shortStdNames 主体简称
* @param condition 条件
* @param graphConditionEnum 条件类型枚举
* @return Between条件
*/
private String buildConditionFormat(Map<String, String> shortStdNames, AutoReqConditionDto condition, GraphConditionEnum graphConditionEnum) throws Exception {
String targetConditionFormat = graphConditionEnum.getTargetConditionFormat();
GraphTypeEnum graphTypeEnum = GraphTypeEnum.returnGraphType(condition.getDbDataType());
String shortStdName = shortStdNames.get(condition.getRootName());
String key = String.format(StringConstant.KEY_FORMAT, shortStdName, condition.getFieldName());
switch (graphConditionEnum) {
case NOT_EMPTY:
case IS_EMPTY:
return String.format(targetConditionFormat, key);
case NOT_BETWEEN_END:
case BETWEEN_END:
return buildBetweenCondition(key, condition.getValue(), targetConditionFormat, graphTypeEnum);
case BOTH_CONTAIN:
case NOT_BOTH_CONTAIN:
return buildBothContainsCondition(key, condition.getValue(), targetConditionFormat);
case MANY_VALUE_CONTAIN:
return buildManyValueCondition(key, condition.getValue(), targetConditionFormat);
default:
return buildNormalCondition(key, condition.getValue(), targetConditionFormat, graphTypeEnum);
}
}
/**
* 构造IN条件
*
* @param key 属性名
* @param value 属性执
* @param targetConditionFormat 条件format
* @return IN条件
*/
private String buildManyValueCondition(String key, Object value, String targetConditionFormat) {
List<String> strList = JSONArray.parseArray(JSONArray.toJSONString(value), String.class);
String condition = buildUniqueKeyCondition(strList);
return String.format(targetConditionFormat, key, condition);
}
/**
* 构造BothContains条件
*
* @param key 属性名
* @param value 属性执
* @param targetConditionFormat 条件format
* @return Between条件
*/
private String buildBothContainsCondition(String key, Object value, String targetConditionFormat) {
List<String> strList = JSONArray.parseArray(JSONArray.toJSONString(value), String.class);
List<String> conditionList = strList.stream().map(str -> String.format(targetConditionFormat, key, str)).collect(Collectors.toList());
String joinCondition = String.join(GraphConditionEnum.AND.name(), conditionList);
return StringConstant.LEFT_LITTLE_BRACKET + joinCondition + StringConstant.RIGHT_LITTLE_BRACKET;
}
/**
* 构造Between条件
*
* @param key 属性名
* @param value 属性执
* @param targetConditionFormat 条件format
* @param graphTypeEnum 数据类型枚举
* @return Between条件
*/
private String buildBetweenCondition(String key, Object value, String targetConditionFormat, GraphTypeEnum graphTypeEnum) {
switch (graphTypeEnum) {
case INT32:
case INT64:
List<Integer> numList = JSONArray.parseArray(JSONArray.toJSONString(value), Integer.class);
return String.format(targetConditionFormat, key, numList.get(NumberConstant.ZERO), key, numList.get(NumberConstant.ONE));
default:
List<String> strList = JSONArray.parseArray(JSONArray.toJSONString(value), String.class);
return String.format(targetConditionFormat, key, strList.get(NumberConstant.ZERO), key, NumberConstant.ONE);
}
}
/**
* 根据条件format,拼接查询语句
*
* @param key 属性key
* @param value 属性value
* @param targetConditionFormat 条件类型对应的format
* @param graphTypeEnum 对应图数据库类型
* @return 条件语句
* @throws ServiceException 不支持的数据类型,如新增了dbDataType
*/
private String buildNormalCondition(String key, Object value, String targetConditionFormat, GraphTypeEnum graphTypeEnum) throws Exception
{
switch (graphTypeEnum) {
case INT32:
case INT64:
try {
List<Integer> numList = JSONArray.parseArray(JSONArray.toJSONString(value), Integer.class);
return String.format(targetConditionFormat, key, numList.get(NumberConstant.ZERO));
} catch (Exception e) {
log.error("条件值转数字异常:{},{},{}", key, value, e.getMessage());
throw new Exception("条件值转数字异常");
}
default:
List<String> strList = JSONArray.parseArray(JSONArray.toJSONString(value), String.class);
return String.format(targetConditionFormat, key, String.format(StringConstant.VALUE_FORMAT, strList.get(NumberConstant.ZERO)));
}
}
/**
* 构建唯一键条件
* 用于复杂查询,biz_id in ('xxx','xxx','xxx','xxx','xxx','xxx')的场景)
*
* @param uniqueValues 唯一键的值
* @return 'xxx','xxx','xxx','xxx','xxx','xxx',注意,字符串需要加上单引号,所以没有使用String.join()
*/
private String buildUniqueKeyCondition(List<String> uniqueValues) {
StringBuilder sb = new StringBuilder();
for (String uniqueValue : uniqueValues) {
if (sb.length() > 0) {
sb.append(StringConstant.COMMA).append(String.format(StringConstant.VALUE_FORMAT, uniqueValue));
} else {
sb.append(String.format(StringConstant.VALUE_FORMAT, uniqueValue));
}
}
return sb.toString();
}
}
三、DbDataTypeEnum 入参的数据类型
import lombok.Getter;
/**
* 数据类型枚举
*/
@Getter
public enum DbDataTypeEnum {
/**
* 1 - 字符型
*/
STRING(1),
/**
* 2 - 加密字符
*/
ENCRYPT_STRING(2),
/**
* 3 - 整型
*/
Integer(3),
/**
* 4 - 字符数组
*/
STRING_ARRAY(4),
/**
* 5 - 加密字符数组
*/
ENCRYPT_STRING_ARRAY(5),
/**
* 6 - 标签对象数组
*/
LABEL_ARRAY(6),
/**
* 7 - 字典对象
*/
DICT(7),
/**
* 8 - 地址对象
*/
ADDRESS(8),
/**
* 9 - 地址对象数组
*/
ADDRESS_ARRAY(9),
/**
* 10 - 网格身份对象数组
*/
GRID_ARRAY(10),
/**
* 11 - 社区职务对象数组
*/
GRID_IDENTIFY(11),
/**
* 12 - 微网格身份对象数组
*/
MICROGRID__ARRAY(12),
/**
* 13 - 特殊字段类型
*/
SPECIAL_FILED(13),
;
private Integer key;
DbDataTypeEnum(Integer key) {
this.key = key;
}
public static DbDataTypeEnum returnDbDataType(int key){
for (DbDataTypeEnum type:DbDataTypeEnum.values()){
if(type.key == key){
return type;
}
}
return null;
}
}
四、GraphTypeEnum 图数据的类型
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
/**
* @Author: zbx
* @CreateTime: 2024-08-19
* @Description: 图数据库基本类型
*/
@Slf4j
@Getter
public enum GraphTypeEnum {
/**
* tuGraph数据库对应的数据类型
*/
INT32,
INT64,
STRING,
DATE,
DATETIME,
BOOL;
public static GraphTypeEnum returnGraphType(int dbDataType) throws Exception {
if (dbDataType == DbDataTypeEnum.STRING.getKey()
|| dbDataType == DbDataTypeEnum.ENCRYPT_STRING.getKey()
|| dbDataType == DbDataTypeEnum.STRING_ARRAY.getKey()
|| dbDataType == DbDataTypeEnum.ENCRYPT_STRING_ARRAY.getKey()
|| dbDataType == DbDataTypeEnum.LABEL_ARRAY.getKey()
|| dbDataType == DbDataTypeEnum.DICT.getKey()
|| dbDataType == DbDataTypeEnum.ADDRESS.getKey()
|| dbDataType == DbDataTypeEnum.ADDRESS_ARRAY.getKey()
|| dbDataType == DbDataTypeEnum.SPECIAL_FILED.getKey()) {
return GraphTypeEnum.STRING;
} else if (dbDataType == DbDataTypeEnum.Integer.getKey()) {
return GraphTypeEnum.INT32;
} else {
log.error("数据类型转换,数据类型不支持:{}", dbDataType);
throw new Exception("数据类型不支持");
}
}
/**
* 返回tuGraph数据库对应的数据类型枚举
*
* @param graphType 数据类型
* @return 数据类型枚举
* @throws Exception 暂不支持的图数据类型
*/
public static GraphTypeEnum getGraphType(String graphType) throws Exception {
for (GraphTypeEnum value : GraphTypeEnum.values()) {
if (value.name().equals(graphType)) {
return value;
}
}
throw new Exception("暂不支持的图数据类型:" + graphType);
}
}
五、工具类 & 静态参数类
NumberConstant
RegexConstant
RegexUtils
StringConstant
public interface NumberConstant {
Integer MINUS_ONE = -1;
Integer ZERO = 0;
Integer ONE = 1;
Integer TWO = 2;
Integer THREE = 3;
Integer FOUR = 4;
Integer FIVE = 5;
Integer TEN = 10;
Integer TWELVE = 12;
Integer THIRTY = 30;
Integer FIFTY = 50;
Integer ONE_HUNDRED = 100;
}
public interface RegexConstant {
//---------------------------------------------------------------- 用于字符串匹配 ------------------------------------------------------------------------
/**
* 匹配()内的内容
*/
String STD_LITTLE_BRACKET_REGEX = "\\((.*?)\\)";
/**
* 匹配[]内的内容
*/
String STD_SQUARE_BRACKET_REGEX = "\\[(.*?)\\]";
/**
* 匹配是否数字
*/
String IS_NUMERIC = "^[-+]?\\d*(\\.\\d+)?$";
/**
* 匹配主体名
*/
String STD_REGEX = "std_\\w+";
/**
* 匹配属性名,属性名通常是:英文+下划线,如:id_card
*/
String PROPERTY_REGEX = "^[a-zA-Z0-9._]*$";
/**
* 匹配运算符:加、减、乘、除,大于、小于、不等于、等于
*/
String OPERATORS = "[+\\-*/>\\<!=\\=]";
/**
* 匹配不区分大小写的聚合函数名
*/
String AGGREGATE_FUNCTION = "(?i)(SUM|AVG|MAX|MIN|COUNT)";
/**
* 匹配不区分大小写的聚合函数名
*/
String AGGREGATE_FUNCTION_NO_COUNT = "(?i)(SUM|AVG|MAX|MIN)";
/**
* 判断字符串中是否含有一个COUNT(
*/
String COUNT_REGEX = "(?i)COUNT\\(";
/**
* 匹配示例:(p:std_people {name:'张三'}) 或 (p:std_people)
*/
String NODE_AND_CONDITIONS = "(\\(\\s*[a-zA-Z0-9_]*:[a-zA-Z0-9_]*+(?:\\s+\\{[^\\}]*\\})?\\s*\\))";
/**
* 做大括号
*/
String LEFT_BIG_BRACE = "\\{";
/**
* 右小括号
*/
String RIGHT_LITTLE_BRACKET = "\\)";
/**
* 匹配label = 'xxx'的模式
*/
String LABEL_EQUAL_REGEX = "(\\w+)\\.label\\s*=\\s*'([^']+)'";
/**
* 替换为label CONTAINS 'xxx'
*/
String LABEL_CONTAINS_REPLACE_REGEX = "$1.label CONTAINS '$2'";
/**
* 匹配label = 'xxx'的模式
*/
String NAME_EQUAL_REGEX = "(\\w+)\\.name\\s*=\\s*'([^']+)'";
/**
* 替换为label CONTAINS 'xxx'
*/
String NAME_EQUAL_REPLACE_REGEX = "($1.name = '$2·$4' OR $1.name = '$2.$4')";
/**
* 匹配label = 'xxx'的模式
*/
String NAME_CONTAINS_REGEX = "(\\w+)\\.name\\s*CONTAINS\\s*'([^']+)'";
/**
* 替换为label CONTAINS 'xxx'
*/
String NAME_CONTAINS_REPLACE_REGEX = "($1.name CONTAINS '$2·$4' OR $1.name CONTAINS '$2.$4')";
String DIRECTION_REGEX = "(<-\\[:[^\\]]*\\]-)|(-\\[:[^\\]]*\\]->)";
//---------------------------------------------------------------- 用于字符串分割 ------------------------------------------------------------------------
/**
* 空格
*/
String STRING_SPILT_BLANK = " ";
/**
* 英文句号分隔符
*/
String STRING_SPILT_POINT = "\\.";
/**
* 冒号分隔符
*/
String STRING_SPILT_COLO = "\\:";
/**
* RETURN分隔符
*/
String STRING_SPILT_RETURN = "RETURN";
/**
* 拼接统计函数
*/
String STRING_COUNT = "COUNT()";
/**
* 分页分隔符
*/
String STRING_LIMIT = "LIMIT";
/**
* 分页偏移量
*/
String STRING_SKIP = "SKIP";
/**
* 拼接返回统计函数
*/
String STRING_RETURN_COUNT = STRING_SPILT_RETURN + STRING_SPILT_BLANK + STRING_COUNT;
// boolean containsFunction = matcher.find();
/**
*
*/
}
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 正则工具类
*
* @author lobster.long
*/
public class RegexUtils {
/**
* 返回字符串中满足正则的第一个结果
*
* @param input 字符串
* @param regex 正则
* @return 满足正则的所有结果
*/
public static String getFirst(String input, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group();
}
return null;
}
/**
* 返回字符串中满足正则的最后一个结果
*
* @param input 字符串
* @param regex 正则
* @return 满足正则的所有结果
*/
public static String getLast(String input, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
String result = null;
while (matcher.find()) {
result = matcher.group();
}
return result;
}
/**
* 返回字符串中满足正则的所有结果
*
* @param input 字符串
* @param regex 正则
* @return 满足正则的所有结果
*/
public static List<String> getList(String input, String regex) {
List<String> result = new ArrayList<>();
Pattern lastPattern = Pattern.compile(regex);
Matcher lastmatcher = lastPattern.matcher(input);
while (lastmatcher.find()) {
result.add(lastmatcher.group(NumberConstant.ONE));
}
return result;
}
/**
* 使用正则表达式匹配,返回匹配结果:true,false
*
* @param input 字符串
* @param regex 正则
* @return 返回匹配结果:true,false
*/
public static boolean regexBool(String input, String regex) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(input);
return matcher.find();
}
/**
* 截取cypher中,最后一个return 之前的内容
*/
public static String getCypherBeforeRegex(String cypher, String regex) {
// // 将原始字符串转换为小写,以便不区分大小写地搜索"return"
// String lowerCaseString = cypher.toUpperCase();
// // 查找"return"(不区分大小写)在字符串中最后一次出现的位置
// int lastIndex = lowerCaseString.lastIndexOf(regex);
int lastIndex = cypher.lastIndexOf(regex);
// 如果找到了"return",则截取它之前的所有内容
// 注意:lastIndexOf返回的是小写字符串中的索引,但我们要在原始字符串上截取,所以索引是有效的
if (lastIndex != -1) {
return cypher.substring(0, lastIndex);
}
return null;
}
/**
* 返回字符串中,最后一个regex后面的内容
*
* @param cypher 待执行语句
* @param regex 指定字符串
* @return 指定字符串后面的内容
*/
public static String getCypherAfterRegex(String cypher, String regex) {
// // 将原始字符串转换为小写,以便不区分大小写地搜索"return"
// String lowerCaseString = cypher.toUpperCase();
// // 查找"return"(不区分大小写)在字符串中最后一次出现的位置
// int lastIndex = lowerCaseString.lastIndexOf(regex);
int lastIndex = cypher.lastIndexOf(regex);
// 如果找到了"return",则截取它之后的所有内容
// 注意:lastIndexOf返回的是小写字符串中的索引,但我们要在原始字符串上截取,所以索引是有效的
if (lastIndex != -1) {
return cypher.substring(lastIndex + regex.length());
}
return null;
}
public static String appendCount(String cypher) {
return cypher + RegexConstant.STRING_RETURN_COUNT;
}
/**
* 匹配字符串中的(p:std_people) 或 (h:std_house {building_no:1}) 将社区编码加入到条件中
*
* @param cypher 待修正语句
* @param nodeAndConditionRegex 正则匹配
* @param communityCode 社区编码
* @return 增加社区编码后的查询语句
*/
public static String addCommunityCodeCondition(String cypher, String nodeAndConditionRegex, String communityCode) {
Pattern pattern = Pattern.compile(nodeAndConditionRegex);
Matcher matcher = pattern.matcher(cypher);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
// 获取匹配的节点定义
String nodeDef = matcher.group(0);
if (nodeDef.contains(StringConstant.BRACE)) {
// 将community_code:'5101'添加到节点定义的属性列表中
String modifiedNodeDef = nodeDef.replaceFirst(RegexConstant.LEFT_BIG_BRACE, String.format(StringConstant.COMMUNITY_CODE_AND_CONDITION, communityCode));
matcher.appendReplacement(sb, modifiedNodeDef);
} else {
// 将community_code:'5101'添加到节点定义的属性列表中
String modifiedNodeDef = nodeDef.replaceFirst(RegexConstant.RIGHT_LITTLE_BRACKET, String.format(StringConstant.COMMUNITY_CODE_NO_CONDITION, communityCode));
matcher.appendReplacement(sb, modifiedNodeDef);
}
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 将字符串中满足正则的部分,全部替换为指定字符串
* 如:将 label = 'sss' 替换为 label CONTAINS 'sss'
*
* @param str 字符串
* @param regex 正则
* @param replacement 替换为指定字符串
* @return 替换后的字符串
*/
public static String replaceAll(String str, String regex, String replacement) {
// 正则表达式匹配regex,如:匹配label = 'abc''的模式
Pattern pattern = Pattern.compile(regex);
// 使用Matcher来替换所有匹配的字符串
return pattern.matcher(str).replaceAll(replacement);
}
/**
* 提取字符串中符合正则的所有字符串
*
* @param str 字符串
* @param regexList 正则匹配
* @return 符合正则的所有字符串
*/
public static List<String> getMatchStrByPatterns(String str, List<String> regexList) {
List<String> matches = new ArrayList<>();
for (String regex : regexList) {
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
// 只提取符合特定格式的匹配项
matches.add(matcher.group(0));
}
}
return matches;
}
/**
* 检查是否有匹配,并且只匹配一次
*
* @param str 字符串
* @param regex 正则
* @return true - 只有一个,false - 有多个
*/
public static Boolean onlyOne(String str, String regex) {
// 编译正则表达式
Pattern pattern = Pattern.compile(regex);
// 创建matcher对象
Matcher matcher = pattern.matcher(str);
// 检查是否有匹配,并且只匹配一次
return matcher.find() && !matcher.find();
}
}
public interface StringConstant {
/**
* -------------------------------------- format --------------------------------
*/
String VERTEX_SCHEME_FORMAT = "CALL db.getVertexSchema('%s')";
String KEY_FORMAT = " %s.%s ";
String VALUE_FORMAT = " '%s' ";
String UNIQUE_KEY_CONDITION_FORMAT = " %s.%s IN [%s] ";
String COUNT_FORMAT = " WITH DISTINCT %s.%s AS 主键 RETURN COUNT(主键) as 总数 ";
String PAGE_DATA_FORMAT = " RETURN DISTINCT %s.%s ";
String SKIP_LIMIT_FORMAT = " SKIP %s LIMIT %s ";
String OR_FORMAT = "( %s OR %s )";
String COMMUNITY_CODE_AND_CONDITION = "{community_code:'%s',";
String COMMUNITY_CODE_NO_CONDITION = " {community_code:'%s'})";
String STD_MATCH_FORMAT = " (%s:%s)";
/**
* 生成MATCH语句
*/
String SIMPLE_MATCH_FORMAT = "MATCH %s %s RETURN %s ";
/**
* 反方向
*/
String REVERSE_DIRECTION_FORMAT = "<-[%s]-";
/**
* -------------------------------------- 常量 --------------------------------
*/
/**
* 字符分隔符 ·
*/
String CH_POINT = "·";
/**
* 字符分隔符 .
*/
String ES_POINT = ".";
/**
* 字符分隔符 .
*/
String EQUAL = "=";
/**
* 字符分隔符 .
*/
String CONTAINS = "CONTAINS";
String STD_OTHER = "other";
String BRACE = "}";
String COMMA = ",";
String UNDERLINE = "_";
String LEFT_LITTLE_BRACKET = " (";
String RIGHT_LITTLE_BRACKET = ") ";
String TOTAL = "总数";
String WHERE = "WHERE";
String AND = "AND";
String COUNT = "COUNT";
String BLANK = " ";
String[] KEYWORDS = {"CREATE", "DELETE", "SET", "REMOVE", "DROP"};
String STD_COMMON = "std_common";
}
总结
执行结果:
虽然不是分组条件,但是将就用吧。