統計字符/子串出現次數是常見文本處理需求。本文提供文件級與內存級兩種實現,並分析時間/空間複雜度。
public static int countInFile(String filePath, String target) throws IOException {
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
StringBuilder sb = new StringBuilder();
String line;
while ((line = br.readLine()) != null) sb.append(line);
return countInString(sb.toString(), target);
}
}
private static int countInString(String text, String target) {
int count = 0, idx = 0;
while ((idx = text.indexOf(target, idx)) != -1) {
count++;
idx += target.length(); // 非重疊匹配;若需重疊用 idx++
}
return count;
}
特點:流式讀取,內存佔用 ≈ 文件大小(可改用 MappedByteBuffer 零拷貝優化)。
// Apache Commons Lang 一行式
int count = StringUtils.countMatches(text, target);
// 或手寫(同上 indexOf 邏輯)
public static int countMatches(String text, String target) {
if (text == null || target == null || target.isEmpty()) return 0;
int count = 0, idx = 0;
while ((idx = text.indexOf(target, idx)) != -1) {
count++;
idx += target.length();
}
return count;
}
public static int countRegex(String text, String regex) {
Matcher m = Pattern.compile(regex).matcher(text);
int count = 0;
while (m.find()) count++;
return count;
}
// 用法:countRegex("ababa", "aba") → 1(非重疊);重疊需用 lookahead "(?=aba)"
| 方法 | 耗時 | 內存 | 適用場景 |
|---|---|---|---|
indexOf 循環 | 最快 | O(1) 額外 | 固定子串、高頻調用 |
StringUtils.countMatches | 快 | O(1) | 通用工具類 |
正則 Matcher.find | 較慢 | O(1) | 模式匹配、重疊統計 |
// 文本 "aaa" 統計 "aa" 出現 2 次(位置 0、1)
public static int countOverlapping(String text, String target) {
int count = 0, idx = 0;
while ((idx = text.indexOf(target, idx)) != -1) {
count++;
idx++; // 只移動一位,允許重疊
}
return count;
}
// 正則寫法:Pattern.compile("(?=" + Pattern.quote(target) + ")")
indexOf 循環 / StringUtils.countMatches。indexOf,避免一次性載入內存。lookahead。commons-lang3 依賴可直接用 StringUtils,生產級項目推薦。