
本文介绍一种基于正则表达式的高效方法,用于处理含空格、括号和逗号混合结构的字符串(如 `"apple orange (banana ice cream, grape)"`),将其准确拆分为语义完整的词项列表,兼顾括号内外逻辑与空格保留。
在实际开发中,我们常需解析非标准格式的自然语言式字符串——例如产品标签、食品配料或用户输入的复合描述。这类字符串往往混合使用空格分隔主项、圆括号包裹可选子项、逗号分隔括号内枚举值,且括号内项本身可能含空格(如 "Banana Ice Cream")。此时,简单的 String.split(" ") 或 split(",") 会破坏语义完整性。
推荐使用 单条正则表达式 统一分割所有关键边界:
- 空格(但仅作为分隔符,不破坏括号内多词项)
- 左括号 ( 和右括号 )
- 逗号 ,(前后允许可选空白)
对应正则模式为:
String DELIMITER = "\\s+|\\(|\\)|\\s*,\\s*";
✅ 解析逻辑说明: \\s+:匹配一个或多个空白字符(统一处理空格/制表符等) \\( 与 \\):转义后分别匹配字面量 ( 和 ) \\s*,\\s*:匹配逗号及其前后任意空白(确保 "Banana, Grape" → ["Banana", "Grape"],而非 ["Banana", " Grape"])
完整示例代码如下:
立即学习“Java免费学习笔记(深入)”;
import java.util.*;
public class StringSplitter {
private static final String DELIMITER = "\\s+|\\(|\\)|\\s*,\\s*";
public static List extractTerms(String input) {
if (input == null || input.trim().isEmpty()) {
return Collections.emptyList();
}
return Arrays.stream(input.split(DELIMITER))
.filter(s -> !s.trim().isEmpty()) // 过滤空字符串(如括号紧邻时产生的空项)
.map(String::trim)
.collect(Collectors.toList());
}
public static void main(String[] args) {
String k1 = "Apple";
String k2 = "Apple Orange";
String k3 = "Apple (Banana, Orange, Grape)";
String k4 = "Apple Orange (Banana, Grape)";
String k5 = "Apple Orange (Banana Ice cream, Grape)";
System.out.println(extractTerms(k1)); // [Apple]
System.out.println(extractTerms(k2)); // [Apple, Orange]
System.out.println(extractTerms(k3)); // [Apple, Banana, Orange, Grape]
System.out.println(extractTerms(k4)); // [Apple, Orange, Banana, Grape]
System.out.println(extractTerms(k5)); // [Apple, Orange, Banana Ice cream, Grape]
}
} ⚠️ 重要注意事项:
- 此方案不校验括号配对(如 "Apple (Banana, Grape" 不报错),适用于输入格式可信的场景;若需强语法校验,应结合栈式解析器或专用解析库(如 ANTLR)。
- 若需严格保留 "Apple Orange" 作为单一元素(如 k2 和 k4 的期望输出),当前正则会将其拆成两项 —— 此时需先分离括号块再分别处理:
// 进阶策略:提取括号外主体 + 括号内列表,再合并 String[] parts = input.split("\\s*\\((.*?)\\)\\s*", 2); // 最多切两段 Listresult = new ArrayList<>(); if (parts.length > 0 && !parts[0].trim().isEmpty()) { result.add(parts[0].trim()); // 主体(保留空格) } if (parts.length > 1 && !parts[1].trim().isEmpty()) { Arrays.stream(parts[1].split("\\s*,\\s*")) .filter(s -> !s.isEmpty()) .map(String::trim) .forEach(result::add); }
综上,正则 \\s+|\\(|\\)|\\s*,\\s* 是平衡简洁性与实用性的首选方案;若业务要求严格保留括号前连续空格项,则建议采用分步提取策略,确保语义无损。










