你完全可以在不建立樞紐分析表的情況下,計算一段文字中某個字串出現的次數,只要使用一個在瀏覽器中執行的「計算出現次數」工具即可。該工具可在本地讀取最多 1,000,000 個字元、傳回符合的總數,並列出前 100 個以零為起始的起始位置。大多數搜尋「如何使用樞紐分析表計算出現次數」的使用者,其實是在 Excel 中工作,而這個問題通常意味著「統計 B 欄中每個值的數量,並顯示每個值各佔幾列」。那種樞紐分析表的做法在工作表內確實非常實用,但同樣的計算問題也經常出現在純文字檔、記錄檔行、程式碼片段、CSV 匯出檔以及貼上的散文中;在這些情境下,要嘛沒有試算表,要嘛試算表太過笨重。而「計算出現次數」工具正好直接處理這種較輕量的情況:貼上來源文字、輸入要尋找的字串、選擇是否區分大小寫以及是否允許重疊,工具就會回傳一個數字結果以及具體的位置。每一個步驟都在你的瀏覽器中執行,不會進行任何上傳,而且搜尋完全是字面比對,因此像句點、方括號、星號這類標點符號都不需要任何跳脫處理。

how to use pivot table to count number of occurrences
如何在不使用樞紐分析表的情況下計算文字中的出現次數

為什麼對一次快速的文字計數而言,樞紐分析表是殺雞用牛刀

當你的資料本身就已經是試算表的形狀、你要統計的欄位是一個真正的欄位,而且你面前已經開啟了 Excel、LibreOffice Calc 或 Google Sheets 時,樞紐分析表就是正確解答。但對於從記錄檔、JSON 匯出檔、聊天記錄或一段冗長的程式碼範例中所複製出的一大塊文字而言,這些條件並不一定都成立。為了確認「timeout」這個字到底出現 14 次還是 17 次,還得特地開啟試算表、匯入文字、將它切成多列、再設定樞紐欄位,這對於一個簡單的數字來說實在是太麻煩了。

「計算出現次數」工具消除了這種麻煩。你貼上來源文字、輸入想要尋找的字面字串、選擇比對時是否區分大小寫、決定是否允許重疊,然後直接讀取結果。輸出包含一個總數以及一小串以零為起始的位置,而且所有運算都在本地端進行,因此敏感的記錄檔與尚未完成的草稿都不會離開這個分頁。對於仍然偏好留在工作表中的 Excel 使用者來說,在 Excel 中不使用公式計算文字出現次數這份指南,會逐步說明如何將同一套工具應用於試算表資料。

逐步計算文字出現次數

整個工作流程都在計算出現次數工具頁面中進行,只要準備好輸入內容,只需要一點點時間就能完成。

  1. 貼上或輸入你想要搜尋的來源文字。你可以貼上最多 1,000,000 個字元。這個工具不會修剪內容、不會正規化換行字元、不會合併空白字元,也不會對輸入內容進行任何刪除處理;你所貼上的內容就是會被搜尋的內容。
  2. 輸入要尋找的字面文字,並選擇是否區分大小寫以及重疊行為。搜尋字串最長可達 1,000 個字元,並且可以包含空格、Tab、換行、表情符號或一般的 Unicode 字元。請選擇區分大小寫或不區分大小寫的比對模式,並選擇允許重疊或不允許重疊的模式。
  3. 計算符合的數量,並查看總數以及前 100 個以零為起始的起始位置。回報的總數絕不會被截斷,但只會列出前 100 個位置,這樣即使結果有數十萬個符合項目,仍然能保持可讀性。編輯任何輸入或選項都會清除舊的計數,因此不可能將一個過時的數字誤認為是當前設定下的結果。

如果你想在全新的文字內容上重新計算,只需替換來源欄位即可。表單下方的輸出會在來源、搜尋字串、大小寫選項或重疊選項變更的瞬間重置,以避免你依據一個已經無法反映螢幕上內容的數字採取行動。

重疊與非重疊模式的說明

在這個表單上,最令人意外的選項就是「重疊」,因為同一個搜尋依據你選擇的模式不同,可能會產生兩種不同的計數結果。非重疊模式是大多數人從試算表 COUNTIF 行為中所沿用的預設心智模型,它會在每次命中後將搜尋指標往後推進整個符合字串的長度。而重疊模式則只會推進一個 JavaScript 字串單位,因此下一次符合可以從前一次符合的內部開始。這兩種行為在 JavaScript String indexOf 參考文件中有詳細說明,這也是整個工具在底層反覆執行的查詢機制。

要看出兩者差異最乾淨的方式,就是在四個字元的來源 aaaa 中搜尋兩個字元的字串 aa。下表顯示了兩種模式各自的回報結果。

模式搜尋字串來源找到的起始位置總計數
非重疊aaaaaa0, 22
重疊aaaaaa0, 1, 23

這個逐步示範的範例會一步一步拆解其運算過程。在非重疊模式下,搜尋從位移 0 開始,立即找到 aa,然後一次跳過完整的搜尋長度 2,到達位移 2,並在此找到第二個 aa,最後以計數 2 結束。在重疊模式下,搜尋從位移 0 開始,找到 aa,但只往前推進 1 個單位到達位移 1,並在此從第二個字元開始找到第二個 aa,接著跳到位移 2 找到第三個符合,最終以計數 3 結束。

當你想要知道一個字面尋找並取代操作會進行多少次獨立的取代時,請使用非重疊模式;當你要進行序列分析,且每一個相鄰的出現位置都很重要時(例如計算一個雙字母組合、三字母組合或重複的 token 在一段文字中連續出現的次數),則請使用重疊模式。

解讀以零為起始的位置編號

工具所列出的每一個位移,都是一個 JavaScript UTF-16 字串索引,這代表你來源中的第一個字元位於位置 0,而不是位置 1。大多數一般的英文字母、數字、空格、Tab 以及常見的標點符號各佔用一個位移,因此位置編號會與你在螢幕上能夠數到的可見字元整齊對應。然而,對於以代理對(surrogate pair)表示的字元(這包括大多數的表情符號以及部分較少見的 CJK 字形),它們會佔用兩個 UTF-16 程式碼單位而非一個,因此一個位於行首的表情符號,會將其後所有位置都額外往後推一個單位。

正因為如此,這個工具對其位置編號的意義是誠實的:它們是可重現的 JavaScript 字串索引,對於瀏覽器主控台操作,以及對應你在字面索引查找中所會看到的位移來說非常有用,但並非對應到人類閱讀者所認知的一個字元的字素索引。如果你將同一段來源貼上兩次,你會得到相同的位移,因為這個工具並不會改寫你的輸入。它也不會執行任何 Unicode 正規化、變音符號合併或地區特定的大小寫規則;只有在開啟不區分大小寫模式時,才會進行一個簡單的英文地區小寫轉換。

計算文字出現次數的實際應用情境

這個工具是一個實用的文字公用程式,而非一套完整的語言分析引擎,而這正好符合大多數臨時性計算工作的需求。常見的用途包括:檢查一個重複的字詞(例如「the the」)是否不小心溜進了草稿中;計算像 Tab、垂直線、分號這類分隔符在類似 CSV 的某一行中出現幾次;統計像 ERROR 或 WARN 這類記錄檔標記在貼上的一段存取記錄中出現幾次;以及驗證某段特定的程式碼片段、識別字或標點字串在一段文字中出現幾次。

你也可以用它來計算精確的片語,包括當搜尋欄位中含有換行字元時橫跨換行位置的片語,並確認某個 ID、票券編號或電子郵件格式的字串在一份匯出內容中重複出現幾次。若要依據來源中每一個相異字詞來分組計數,而非依據單一指定的字串,請改用字數統計工具。若想要變更這些符合項目而不只是計算它們,則可以使用「尋找並取代」工具,它以相同的字面比對規則並搭配一個取代欄位來處理。若要並排比較兩段文字,則「文字差異比對工具」會是更合適的選擇。

限制、邊界情況以及這個工具做不到的事

為了讓工具保持回應迅速,並避免一個不小心產生的龐大結果凍結整個分頁,這裡設定了一些實際的限制。來源文字上限為 1,000,000 個字元,搜尋字串上限為 1,000 個字元,兩者都遠超過大多數人為了快速計數所會貼上的片段大小。空白的搜尋字串會被拒絕,因為它會在每一個字元邊界都符合,並產生一個意義不明的結果。當搜尋長度超過剩餘來源時,會回傳零,這是正確的結果而非錯誤。

這個工具刻意不會編譯正規表示式,因此不存在「無效樣式」這類會導致搜尋中斷的概念。句號只會符合字面上的句號、星號只會符合字面上的星號,方括號也不帶有任何特殊語法。同樣地,這個工具不提供全字模式、模糊比對、詞幹化處理、萬用字元語法、Unicode 正規化、取代動作,也沒有檔案上傳解析器。你所看到的結果就只是計數以及前 100 個位置,並不會產生任何下載檔案,因為核心輸出本身就只有一個小小的數字答案。

不區分大小寫模式會在比較之前,以英文地區的小寫轉換規則同時處理來源與搜尋文字,但列印出來的位移仍然是依據原始文字所測量。這使得輸出在各瀏覽器之間具有可預測性,但也代表地區特定的等價規則、組合型與分解型的 Unicode 形式、變音符號合併,以及特定文字系統的大小寫規則都不會被推斷出來;如果你需要上述任何一項處理,請將這個工具視為一個起點,並手動再次核對結果。

如果你正在權衡各種選項,如何精準計算 Google Docs 中的行數對此有詳細的說明。