Java 正则表达式中实现“无嵌套时将整个值作为键、空字符串为值”的灵活解析

本文介绍如何在 java 中使用正则表达式动态区分两种结构:当括号内为纯值(如 `value(123)`)时,将其整体作为 inner map 的键、值设为空字符串;当为嵌套键值对(如 `outervalue(innervalue(123)othervalue(456))`)时,则正常提取子键值对。核心在于先匹配外层结构,再通过预检判断是否需降级为单键解析。

要实现题目所需的语义解析——即对 VALUE(123) 解析为 {123=""},而对 OUTERVALUE(INNERVALUE(123)OTHERVALUE(456)) 解析为 {INNERVALUE="123", OTHERVALUE="456"}——关键不在于“重置捕获组编号”,而在于逻辑分支控制:先识别外层键,再根据其值内容的结构决定 inner map 的构建策略。

核心思路

  • 外层匹配:用 ([A-Z]+)\((.*)\) 提取 KEY(...) 中的 KEY 和括号内全部内容;
  • 结构判别:检查括号内内容是否不含嵌套键值结构(即无形如 XXX(YYY) 的子模式),可借助 Pattern.asPredicate() 高效预检;
  • 双路径解析
    • 若无嵌套 → 将整个 value 字符串作为 inner map 的唯一键,值设为 "";
    • 若有嵌套 → 用更严谨的 ([A-Z]+)\(([^()]*)\)(禁止跨层括号)逐个提取子键值对。
? 为什么改用 ([^()]*)?原 .*? 在贪婪上下文中易跨括号匹配(如 INNERVALUE(123)OTHERVALUE(456) 中可能错误匹配到 INNERVALUE(123)OTHERVALUE),而 [^()]* 明确限定内部不能含括号,确保每个 XXX(YYY) 独立、无嵌套干扰。

✅ 完整可运行代码

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class RegexNestedParser {
    public static void main(String[] args) {
        // 外层模式:匹配 KEY(...)
        Pattern outerPattern = Pattern.compile("([A-Z]+)\\((.*)\\)");
        // 内层模式:安全匹配 XXX(YYY),要求 YYY 不含括号(防跨组)
        Pattern innerPattern = Pattern.compile("([A-Z]+)\\(([^()]*)\\)");

        String input = """
            VALUE(123)
            OUTERVALUE(INNERVALUE(123)OTHERVALUE(456))
            SIMPLE(abc)
            COMPLEX(A(1)B(2)C(3))
            """;

        Map> outer = new HashMap<>();

        for (String line : input.split("\n")) {
            line = line.trim();
            if (line.isEmpty()) continue;

            Matcher outerMatcher = outerPattern.matcher(line);
            if (!outerMatcher.find()) continue; // 跳过非法行

            String key = outerMatcher.group(1);
            String value = outerMatcher.group(2);
            Map innerMap = new HashMap<>();

            // 判定 value 是否含嵌套键值结构
            if (!innerPattern.asPredicate().test(value)) {
                // 无嵌套 → 整个 value 作键,值为空字符串
                innerMap.put(value, "");
            } else {
                // 有嵌套 → 逐个提取子键值对
                Matcher innerMatcher = innerPattern.matcher(value);
                while (innerMatcher.find()) {
                    innerMap.put(innerMatcher.group(1), innerMatcher.group(2));
                }
            }
            outer.put(key, innerMap);
        }

        System.out.println(outer);
        // 输出:{VALUE={123=}, OUTERVALUE={INNERVALUE=123, OTHERVALUE=456}, SIMPLE={abc=}, COMPLEX={A=1, B=2, C=3}}
    }
}

⚠️ 注意事项

  • 输入格式强依赖:本方案假设每行仅一个外层键值对,且括号严格配对、无转义或注释干扰;
  • 性能友好:asPredicate().test() 是轻量预检,避免无效 matcher 创建;
  • 扩展性提示:若未来需支持多层嵌套(如 A(B(C(1)))),应改用递归下降解析器或栈式分析,正则不再适用;
  • 空值处理:示例中统一用空字符串 "" 表示无显式值,如需 null,请将 innerMap.put(value, "") 改为 innerMap.put(value, null)。

该方案以清晰的控制流替代复杂正则技巧,兼顾可读性、健壮性与可维护性,是处理此类半结构化文本的推荐实践。