
本文介绍一种正则表达式方案,用于精准移除字符串末尾的括号及其内容,同时保留符合 (YYYY-YYYY) 格式的日期范围(如 (1920-1988)),避免误删或过度匹配。
本文介绍一种正则表达式方案,用于精准移除字符串末尾的括号及其内容,同时保留符合 `(yyyy-yyyy)` 格式的日期范围(如 `(1920-1988)`),避免误删或过度匹配。
在实际文本处理中,常需清理冗余括号内容——例如用户输入、爬取标题或日志数据中末尾的注释性括号(如 Project Alpha (draft) 或 Version 2.1 (internal only))。但若简单用 ([^)]*)$ 全局匹配,极易误伤合法日期范围(如 (1920-1988)),甚至因贪婪/嵌套问题导致错误截断。
✅ 正确方案采用负向先行断言(negative lookahead)+ 精确边界控制,确保仅匹配「行尾处、非日期格式」的括号组:
s*(?!\d{4}\p{Pd}\d{4}\)[^()]+)\s*$
对应 Java 中的完整写法(注意转义):
String cleaned = input.replaceAll("\s*\((?!\d{4}\p{Pd}\d{4}\))[^()]+\)\s*$", "");
? 正则逐段解析:
- s*(:匹配行尾前可选空格 + 左括号;
- (?!\d{4}\p{Pd}\d{4}\)):关键防护——断言后续不构成 YYYY-YYYY) 形式(p{Pd} 匹配任意短横线类 Unicode 连字符,兼容 -、‑、‒ 等);
- [^()]+:安全匹配括号内任意非括号字符(避免嵌套干扰);
- )\s*$:匹配右括号 + 行尾前可选空格 + 字符串终点。
? 注意事项:
- 该正则仅作用于单行末尾($ 锚定),不跨行匹配;
- 不处理空括号 ()(因 [^()]+ 要求至少一个字符),如需支持,可改为 [^()]*;
- 若目标环境不支持 p{Pd}(如旧版 Java),可简化为 (?!\d{4}-\d{4}\));
- 对含多个末尾括号的字符串(如 text (a) (b)),本模式仅移除最后一个;如需全部移除,需配合循环或更复杂逻辑。
? 实际测试用例验证: | 输入 | 输出 | 说明 | |------|------|------| | foo bar (blah) | foo bar | ✅ 成功移除 | | foo bar (blah) blah (blah) | foo bar (blah) blah | ✅ 仅删末尾一组 | | some (blah) data | some (blah) data | ❌ 不在行尾,不匹配 | | event (1920-1988) | event (1920-1988) | ✅ 日期格式被跳过 | | name () | name () | ❌ 空括号不匹配([^()]+ 失败)|
此方案兼顾准确性与健壮性,适用于 Java、JavaScript(需调整 $ 为 /m 模式)、Python 等主流语言,是处理“条件性括号清理”任务的推荐实践。











