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

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


前言

最近做了这个功能,根据不同的入参生产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";


}

总结

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值