首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 字串計算子字串出現次數:indexOf 迴圈與正則表達式兩種實作

     編輯:Java 相關知識

計算子字串在主字串中出現次數是常見文本處理任務。本文提供兩種核心實作:indexOf 迴圈 (高效能、無正則開銷) 與正則表達式 (功能豐富、支援重疊匹配),並分析效能與邊界情況。

場景範例

String text = "javascriptjavasejavaeejavame";
String target = "java";
// 預期結果:4 次 (java-script, java-se, java-ee, java-me)

方法一:indexOf 迴圈 (推薦、高效能)

public static int countOccurrences(String text, String target) {
    if (text == null || target == null || target.isEmpty()) return 0;

    int count = 0;
    int index = 0;
    while ((index = text.indexOf(target, index)) != -1) {
        count++;
        index += target.length(); // 移至匹配結束處,避免重疊匹配
    }
    return count;
}

關鍵點

  • indexOf(String, int fromIndex):從指定索引開始搜尋,回傳找到位置或 -1
  • index += target.length():非重疊匹配 (標準定義)。若需重疊匹配 (如 "aaa" 中 "aa" 出現 2 次),改為 index++
  • 時間複雜度:O(n*m) 最壞,實際極快 (Boyer-Moore 類似優化)
  • 空間複雜度:O(1)

方法二:正則表達式 (功能豐富)

public static int countOccurrencesRegex(String text, String target) {
    if (text == null || target == null || target.isEmpty()) return 0;

    // Pattern.quote 避免目標字串中的特殊正則字元 (. * + ? 等) 被解釋
    Pattern pattern = Pattern.compile(Pattern.quote(target));
    Matcher matcher = pattern.matcher(text);

    int count = 0;
    while (matcher.find()) {
        count++;
    }
    return count;
}

重疊匹配正則 (Positive Lookahead)

// 若需重疊匹配:(?=pattern) 零寬斷言
public static int countOverlappingRegex(String text, String target) {
    if (text == null || target == null || target.isEmpty()) return 0;
    Pattern pattern = Pattern.compile("(?=" + Pattern.quote(target) + ")");
    Matcher matcher = pattern.matcher(text);
    int count = 0;
    while (matcher.find()) count++;
    return count;
}

// 測試
"aaaa".countOccurrencesRegex("aa")        // 2 (非重疊)
"aaaa".countOverlappingRegex("aa")        // 3 (重疊: 0-1, 1-2, 2-3)

效能對比 (JMH 參考,字串長度 10萬,目標長度 4)

Method                    | Throughput (ops/ms) | Notes
--------------------------|---------------------|-------
indexOf loop              | 1,200               | 基準,最快
Regex (非重疊)            | 320                 | ~3.7x 慢,Pattern 編譯/匹配開銷
Regex (重疊 Lookahead)    | 180                 | 額外零寬斷言開銷
String.split(target).length-1 | 210            | 建立陣列開銷大,不推薦

邊界情況處理

輸入indexOf 迴圈正則備註
text=null0 (需檢查)0 (需檢查)建議拋出 IllegalArgumentException
target=""0 (需檢查)拋出 PatternSyntaxException空字串無意義,必須攔截
target 比 text 長00正常
Unicode 補充字符 (Emoji)正確 (按 code point)正確Java 字串按 UTF-16 code unit,補充字符佔 2 個 char,但 indexOf 按 code point 處理

進階:預編譯 Pattern 供重複使用

public class SubstringCounter {
    private final Pattern pattern;

    public SubstringCounter(String target, boolean overlapping) {
        String regex = overlapping ? "(?=" + Pattern.quote(target) + ")" : Pattern.quote(target);
        this.pattern = Pattern.compile(regex);
    }

    public int count(String text) {
        if (text == null) return 0;
        Matcher m = pattern.matcher(text);
        int c = 0;
        while (m.find()) c++;
        return c;
    }
}

// 使用
SubstringCounter counter = new SubstringCounter("java", false);
int n = counter.count("javascriptjavasejavaeejavame"); // 4

總結建議

  • 標準非重疊計數:優先使用 indexOf 迴圈,零依賴、最高效能、程式碼簡潔
  • 重疊計數:使用 (?=pattern) 正則
  • 複雜匹配規則 (忽略大小寫、詞邊界、通配符) → 正則表達式
  • 高頻重複計數同一目標:預編譯 Pattern 實例複用
  • 大檔案流式計數:逐行讀取 + indexOf 迴圈,避免載入整檔案

此兩種方法涵蓋 99% 子字串計數場景,indexOf 迴圈為效能首選,正則為功能備選。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved