You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Java正则split实现支持value含括号的搜索条件解析

问题说明

当前基于StringTokenizer实现的搜索条件解析逻辑,以()作为全局分隔符拆分token,仅支持value中不含括号的场景,支持的基础查询格式为:

  • (key:operator:value)
  • (key:operator:value) and (key:operator:value)

原有实现代码如下:

Stack<Object> stack = new Stack<>();
StringTokenizer tokenizer = new StringTokenizer(filterString, "()", true);

while (tokenizer.hasMoreElements()) {
    String token = tokenizer.nextToken();

    if (isOpenBrace(token)) {
        stack.push(token);
    } else if (isCloseBrace(token)) {
        Object preVal = null;
        Criteria criteria = null;
        String operator = null;

        while (!isOpenBrace(stack.peek())) {
            Object top = stack.pop();

            if (isString(top)) {
                String op = (String) top;

                if (isAnd(op) || isOr(op)) {
                    operator = (String) top;
                } else {
                    throw new Exception("Invalid operand");
                }
            } else if (isCriteria(top)) {
                if (preVal != null) {
                    if (isAnd(operator)) {
                        top = ((Criteria) top).and((Criteria) preVal);
                        criteria = (Criteria) top;
                        preVal = top;
                    } else if (isOr(operator)) {
                        top = ((Criteria) top).or((Criteria) preVal);
                        criteria = (Criteria) top;
                        preVal = top;
                    }
                } else {
                    preVal = top;
                    criteria = (Criteria) preVal;
                }
            }
        }

        if (criteria != null) {
            stack.pop();
            stack.push(criteria);
        }
    } else if (isAnd(token) || isOr(token)) {
        stack.push(token);
    } else {
        String[] parts = token.split(COLON);
        // do rest stuffs
    }
}

if (stack.size() != 1) {
    throw new Exception("Invalid filter");
}

说明:Criteria为项目内部自定义类。

需要改造分词逻辑,改用split()搭配正则实现,要求仅将作为条件块边界的括号拆分为独立token,value内部的括号保留在内容中:例如输入(key:operator:va(lue)时,分词结果为"(", "key:operator:va(lue)", ")"。

实现方案

核心思路是仅识别作为语法边界的括号:语法边界的括号有明确的上下文特征,不会和value内部的括号混淆:

  • 语法左括号(:要么是字符串首字符,要么紧接在and/or逻辑符之后
  • 语法右括号):要么是字符串尾字符,要么紧接在and/or逻辑符之前

具体实现步骤:

  1. 先对输入字符串做空白归一化,统一逻辑符前后的空格格式,避免多空格、制表符干扰匹配
  2. 用正则零宽断言定位所有语法括号的位置,在语法括号前后插入特殊分隔符(选用业务文本不会出现的\0空字符即可)
  3. 按特殊分隔符拆分字符串,过滤空值、去除每个token前后空白,就得到符合要求的token序列

代码实现

// 输入示例
String filterString = "(key:operator:va(lue)";
// 1. 空白归一化:统一逻辑符前后为单个空格,去除首尾空白
String normalized = filterString.trim()
        .replaceAll("\\s+and\\s+", " and ")
        .replaceAll("\\s+or\\s+", " or ");
// 2. 给语法括号前后加分隔符
// 匹配规则:
// 语法左括号:位于字符串开头 或 空格+and/空格+or 之后
// 语法右括号:位于字符串结尾 或 空格+and/空格+or 之前
String withDelimiter = normalized
        .replaceAll("(^|(?<= and )|(?<= or ))\\(", "\0(\0")
        .replaceAll("\\)(?=$|(?= and )|(?= or ))", "\0)\0");
// 3. 拆分并过滤空token
List<String> tokens = Arrays.stream(withDelimiter.split("\0"))
        .map(String::trim)
        .filter(s -> !s.isEmpty())
        .collect(Collectors.toList());

// 测试输出:[(, key:operator:va(lue), )],完全符合预期
System.out.println(tokens);

拿到token列表后,直接替换原来的StringTokenizer遍历逻辑即可,原有栈解析的代码不需要做任何修改,就可以自动支持value中包含任意括号的场景。

注意:如果业务场景下value内部可能出现前后带空格的and/or子串,需要额外增加转义规则(比如用引号包裹value、转义字符标记内容中的逻辑符),避免被误识别为语法边界。

内容的提问来源于stack exchange,提问作者BuggyBeing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 11:27:17