
本文介绍使用正则表达式 `split("(?
在自然语言处理或自定义词法解析器(如 Tokenizer 类)中,常需将单词按固定粒度(如双字母组)进行切分。题目要求:对 Reader 类中筛选出的大写英文单词(如 "TEACHER" → "Te", "ac", "her"),无论原始字符串长度为奇数或偶数,均严格拆分为三段,每段尽可能为两个字符,剩余字符归入最后一段。例如:
- "TEACHER"(7 字符,奇数)→ ["TE", "AC", "HER"]
- "CATTLE"(6 字符,偶数)→ ["CA", "TT", "LE"]
该需求本质上是「每 2 个字符切一刀,但只切两刀,形成三段」,而非简单等长分片。Java 中最简洁、健壮的实现方式是使用 正则表达式的边界匹配,而非手动计算索引或循环拼接。
✅ 推荐方案:正则 split() 配合 \G 锚点
核心正则表达式:
str.split("(?<=\\G..)(?=..)")- (?正向后查找(lookbehind):匹配位置前必须紧邻「上一次匹配结束处(\G)之后的两个字符」;
- (?=..) 是正向前查找(lookahead):匹配位置后必须至少还有两个字符;
- 二者共同作用,在每两个字符之后、且后面仍有字符时“插入分割点”,从而自然实现「两两分组」,且自动兼容奇偶长度——末尾剩余 1 或 2 字符均保留在最后一段。
? 注意:\G 表示上一匹配的结束位置(或字符串开头),配合 .. 确保每次匹配都从上一轮切分后的位置继续推进,避免重叠或遗漏。
? 完整可运行示例(整合 Reader + Tokenizer)
首先修正原代码中的关键问题:
立即学习“Java免费学习笔记(深入)”;
- Tokenizer 中未导入 java.util.Arrays,导致 Arrays.toString() 报错;
- 原 splitString() 方法错误地对每个字符串调用 Arrays.toString(),得到的是 [T, e, a, c, h, e, r] 这类单字符数组字符串,而非目标双字母组;
- 应对每个字符串单独 split(),再将结果 String[] 存入列表(如 List
)或展平为 List 。
以下是优化后的 Tokenizer.splitString() 实现:
import java.util.*;
import java.util.stream.Collectors;
public class Tokenizer {
private final Reader rd = new Reader();
public List splitString() {
List words = rd.getWord(); // 获取大写单词列表,如 ["PRINTER", "AIRPORT", ...]
return words.stream()
.map(word -> word.split("(?<=\\G..)(?=..)")) // 每词拆为 String[]
.collect(Collectors.toList());
}
// 若需扁平化为单层字符串列表(所有子串合并):
public List splitAndFlatten() {
List words = rd.getWord();
return words.stream()
.flatMap(word -> Arrays.stream(word.split("(?<=\\G..)(?=..)")))
.collect(Collectors.toList());
}
} 调用并验证输出:
public class Main {
public static void main(String[] args) {
Tokenizer tokenizer = new Tokenizer();
List result = tokenizer.splitString();
for (String[] parts : result) {
System.out.println(Arrays.toString(parts));
}
}
} 输出结果:
[PR, IN, TER] [AI, RP, ORT] [PA, IN, TER] [LE, TT, ER] [VE, HI, CLE] [TE, AC, HER]
✅ 完全符合题目要求:"TER"(3 字)、"ORT"(3 字)、"CLE"(3 字)、"HER"(3 字)均为末段保留余数;偶数长词如 "LETT" → "LE", "TT", "ER"(注意原 "Letter" 经 toUpperCase() 后为 "LETTER",长度 6 → "LE", "TT", "ER")。
⚠️ 注意事项与最佳实践
- 不要在循环中反复创建 Reader 实例:当前设计中 Tokenizer 每次调用都新建 Reader,虽无错但低效。建议通过构造函数注入或使用单例模式。
- 空字符串与边界长度需防御:若输入字符串长度
- 性能考量:正则 split() 在大数据量下略慢于 substring() 手动切分,但代码可读性与维护性显著更高。万级以下单词处理无需优化。
- 区分大小写:Reader.wordCheck() 已调用 .toUpperCase(),故切分基于大写字符串,符合示例输出风格。
✅ 总结
使用 str.split("(?










