当前位置: 首页 > news >正文

条件拼接 - 根据入参生成where条件

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

条件拼接 - 根据入参生成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 ANDif (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";}

总结

执行结果:
在这里插入图片描述

虽然不是分组条件,但是将就用吧。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 15 种高级 RAG 技术 ——从预检索到生成
  • zabbix对接Grafana
  • turtlebot 测试 Gazebo Harmonic ROS Jazzy
  • 新安装的mariadb 对应的my.cnf 对应的配置
  • 配置PXE预启动执行环境:使用PXE装机服务器网络引导装机
  • uni-app - - - - - 自定义状态栏
  • 基于STM32与INA219的智能充电桩方案:实时电压监测、费用计算及MySQL云端数据管理的全面技术解析(代码示例)
  • 网络应用层之(2)DNS协议
  • 前端宝典十五:设计模式之前端开发5大设计原则
  • Vue3搜索框(InputSearch)
  • 第七届MathorCup高校数学建模挑战赛-A题:基于改进的神经网络和混沌时间序列预测控制高炉炼铁过程
  • 工作中的所思所想(一)
  • 搭建自己的金融数据源和量化分析平台(七):定时更新上市公司所属行业门类及大类
  • Web中的Cookie与Session
  • 对象存储服务MinIO
  • 分享一款快速APP功能测试工具
  • 【EOS】Cleos基础
  • eclipse的离线汉化
  • ES6语法详解(一)
  • ESLint简单操作
  • go append函数以及写入
  • Invalidate和postInvalidate的区别
  • java取消线程实例
  • magento2项目上线注意事项
  • Redis在Web项目中的应用与实践
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • yii2权限控制rbac之rule详细讲解
  • 阿里云爬虫风险管理产品商业化,为云端流量保驾护航
  • 关于 Linux 进程的 UID、EUID、GID 和 EGID
  • 规范化安全开发 KOA 手脚架
  • 缓存与缓冲
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 使用阿里云发布分布式网站,开发时候应该注意什么?
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 赢得Docker挑战最佳实践
  • 优化 Vue 项目编译文件大小
  • TPG领衔财团投资轻奢珠宝品牌APM Monaco
  • !!java web学习笔记(一到五)
  • #WEB前端(HTML属性)
  • (11)MATLAB PCA+SVM 人脸识别
  • (4) openssl rsa/pkey(查看私钥、从私钥中提取公钥、查看公钥)
  • (done) ROC曲线 和 AUC值 分别是什么?
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • (南京观海微电子)——COF介绍
  • (七)Knockout 创建自定义绑定
  • (一)springboot2.7.6集成activit5.23.0之集成引擎
  • (转)用.Net的File控件上传文件的解决方案
  • .DFS.
  • .NET Core 发展历程和版本迭代
  • .Net OpenCVSharp生成灰度图和二值图
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET Standard、.NET Framework 、.NET Core三者的关系与区别?
  • .Net 访问电子邮箱-LumiSoft.Net,好用
  • .NET8 动态添加定时任务(CRON Expression, Whatever)
  • .NET中使用Protobuffer 实现序列化和反序列化