1. 概述
在文本处理中,从特定模式中提取内容是常见需求。当处理使用方括号封装重要信息的数据时,提取方括号内的文本可能会成为挑战。
本文将探讨提取方括号内文本的技术和方法,主要使用Java正则表达式(regex)作为核心解决方案。
2. 问题背景
为简化问题,我们先做两个前提假设:
- ✅ 无嵌套方括号对 —— 例如
"[value1 [value2]]"
这样的输入不会出现 - ✅ 方括号总是成对出现 —— 例如
"[value1..."
属于无效输入
方括号包裹的数据通常分两种场景:
- 单对方括号输入:如
"some text [value] something else"
- 多对方括号输入:如
"[value1] [value2] [value3]..."
我们将先解决单对方括号场景,再扩展到多对场景。核心工具:Java正则表达式
3. 单对方括号输入
给定输入示例:
String INPUT1 = "some text [THE IMPORTANT MESSAGE] something else";
目标提取内容:
String EXPECTED1 = "THE IMPORTANT MESSAGE";
3.1. \[.*\]
模式
直接思路是提取 [
和 ]
之间的内容,自然想到正则 \[.*\]
。但需注意:
- ⚠️
[
和]
在正则中用于定义字符类(如[0-9]
匹配数字) - 必须转义才能匹配字面量
[
或]
通过捕获组简化提取:
String result = null;
String rePattern = "\\[(.*)]"; // 转义[,]无需转义
Pattern p = Pattern.compile(rePattern);
Matcher m = p.matcher(INPUT1);
if (m.find()) {
result = m.group(1); // 获取捕获组内容
}
assertThat(result).isEqualTo(EXPECTED1);
踩坑提示:只需转义
[
。因为]
前没有未转义的[
时,正则引擎会将其视为字面量。
3.2. 使用NOR字符类
另一种思路:方括号内内容 = 非 ]
的字符序列。利用NOR字符类 [^]]
实现:
String result = null;
String rePattern = "\\[([^]]*)"; // 匹配[后跟任意非]字符
Pattern p = Pattern.compile(rePattern);
Matcher m = p.matcher(INPUT1);
if (m.find()) {
result = m.group(1);
}
assertThat(result).isEqualTo(EXPECTED1);
3.3. 使用 split()
方法
Java的 String.split()
支持正则分隔符。对于 "prefix[value]suffix"
:
- 用
[
或]
分割后得到数组:{"prefix", "value", "suffix"}
- 取中间元素(索引1)即为目标值
String[] strArray = INPUT1.split("[\\[\\]]"); // 分割[和]
String result = strArray.length == 3 ? strArray[1] : null;
assertThat(result).isEqualTo(EXPECTED1);
踩坑警告:当输入以
]
结尾时(如"[value]"
),默认split()
会丢弃尾部空字符串:String[] strArray = "[THE IMPORTANT MESSAGE]".split("[\\[\\]]"); assertThat(strArray).hasSize(2) .containsExactly("", "THE IMPORTANT MESSAGE"); // 缺少尾部空元素
解决方案:传入负数 limit
保留空元素:
String[] strArray = INPUT1.split("[\\[\\]]", -1); // 保留空元素
String result = strArray.length == 3 ? strArray[1] : null;
...
4. 多对方括号输入
新输入示例:
final String INPUT2 = "[La La Land], [The last Emperor], and [Life of Pi] are all great movies.";
目标提取结果:
final List<String> EXPECTED2 = Lists.newArrayList("La La Land", "The last Emperor", "Life of Pi");
4.1. \[(.*)\]
模式——非贪婪版本
直接使用单对方案会失败,因为正则默认贪婪匹配:
// 错误示例:贪婪匹配会捕获 "[La La Land], [The last Emperor], [Life of Pi"
String rePattern = "\\[(.*)]";
解决方案:添加 ?
启用非贪婪匹配,并用循环提取所有匹配:
List<String> result = new ArrayList<>();
String rePattern = "\\[(.*?)]"; // 非贪婪匹配
Pattern p = Pattern.compile(rePattern);
Matcher m = p.matcher(INPUT2);
while (m.find()) { // 循环提取所有匹配
result.add(m.group(1));
}
assertThat(result).isEqualTo(EXPECTED2);
4.2. 使用字符类
NOR字符类方案同样适用,只需将 if
改为 while
循环:
List<String> result = new ArrayList<>();
String rePattern = "\\[([^]]*)"; // NOR字符类
Pattern p = Pattern.compile(rePattern);
Matcher m = p.matcher(INPUT2);
while (m.find()) {
result.add(m.group(1));
}
assertThat(result).isEqualTo(EXPECTED2);
4.3. 使用 split()
方法
多对方括号输入的分割结果示例:
输入: "---[value1]---[value2]---[value3]---"
数组: "---", "value1", "---", "value2", "---", "value3", "---"
索引: [0] [1] [2] [3] [4] [5] [6]
核心规律:所有奇数索引(1,3,5...)的元素为目标值:
List<String> result = new ArrayList<>();
String[] strArray = INPUT2.split("[\\[\\]]", -1); // 保留空元素
for (int i = 1; i < strArray.length; i += 2) { // 遍历奇数索引
result.add(strArray[i]);
}
assertThat(result).isEqualTo(EXPECTED2);
5. 总结
本文系统介绍了Java中提取方括号内文本的多种方案:
- ✅ 正则表达式方案(贪婪/非贪婪模式 + NOR字符类)
- ✅
split()
方案(需处理边界情况)
核心要点:
- 单对方括号场景:直接捕获组或NOR字符类即可
- 多对方括号场景:需启用非贪婪匹配或循环提取
split()
方案需注意尾部空元素处理
源码获取:完整示例代码见 GitHub仓库