為什麼需要這段程式碼
手動修改幾十個檔案的內容很累。如果只是改一個字還好,但如果要改符合特定規則的文字,手動操作幾乎不可能。這段 Python 腳本就是為了解決這個問題。它能幫你快速搜尋資料夾,找到符合條件的檔案,並用正則表達式進行批次替換。這對處理程式碼版本號、路徑更新或大量文件修改非常有用。
如何開始使用
下載程式碼:
https://github.com/max32002/MaxFontScripts/blob/master/replace_string.py
確保你的電腦已經安裝了 Python 3 環境。你可以透過終端機或命令提示字元來執行它。
基本的文字替換
最簡單的用法是直接替換特定的單字。如果你有一個資料夾叫做 docs,裡面有很多文件要把 Apple 改成 Orange,你可以輸入指令。
python replace_string.py ./docs "Apple" "Orange"
這會掃描 docs 資料夾下的所有檔案。只要看到 Apple 就會換成 Orange。程式會自動過濾無法開啟的檔案。修改成功的檔案會顯示在畫面上。
使用正則表達式處理複雜規則
這段腳本強大的地方在於支援正則表達式。假設你有很多設定檔,裡面的版本號可能是 v1.0 或 v2.5。你想把所有 v 開頭加上數字的版本號都統一改成 v3。你可以利用正則表達式的符號。
python replace_string.py ./project "v\d+" "v3"
這裡的 v\d+ 代表一個 v 後面接一個以上的數字。這比單純的關鍵字搜尋更靈活。它能一次處理所有符合規則的變動。
指定特定的檔案類型
有時候你不想動到資料夾裡的所有檔案。例如你只想修改副檔名是 .conf 的設定檔。這時候可以在指令最後面加上過濾條件。
python replace_string.py ./config "127.0.0.1" "0.0.0.0" "*.conf"
這樣腳本就只會檢查 .conf 結尾的檔案。這能避免誤動到圖片或執行檔。這對保護專案中的其他檔案非常安全。
運作原理與安全機制
腳本在修改時會先建立一個暫存檔。它會逐行讀取原檔案,處理完後寫入暫存檔。如果內容真的有變動,才會取代舊檔案。如果內容完全一樣,就會刪除暫存檔。這種做法能防止程式執行到一半出錯,導致原本的檔案損毀。
使用前的小提醒
雖然腳本有安全機制,但批次修改依然有風險。建議在執行大量替換前,先備份你的資料夾。你可以先拿一個小檔案做測試。確認正則表達式的結果符合預期後,再對整個專案執行。這是一個好習慣。
想試試看對特定目錄下的所有 Markdown 檔案進行標題格式轉換嗎?
實戰演練調整標題層級
假設你寫了很多筆記,但發現一級標題太大了。你想把所有 Markdown 檔案的一級標題改成二級標題。這在整理文件架構時非常有幫助。手動改一百個檔案會耗費太多時間。
具體的執行指令
你可以使用正則表達式來精確定位標題。開啟終端機並切換到腳本所在的目錄。輸入下面的指令。
python replace_string.py ./my_notes "^#\s" "## " "*.md"
這裡的 ^#\s 是關鍵。^ 代表每一行的開頭。# 是我們要找的符號。\s 代表空白鍵。這樣可以確保只會改到真正的標題。它不會動到內文中間出現的井字號。
執行後的結果
程式會掃描 my_notes 資料夾下所有的 .md 檔案。它會把每一行開頭的井字號多加一個。處理完後你會看到螢幕顯示哪些檔案已經被修改。如果檔案裡面沒有符合條件的內容,程式會顯示無變動。
檢查與備份
在執行這類批次修改前,建議先備份資料夾。你可以先複製一份複本出來。或者先對單一檔案執行測試。確認轉換邏輯完全正確。這能避免正則表達式寫錯導致檔案內容亂掉。
正則表達式的基本邏輯
正則表達式其實就是一種文字的「特徵描述」。它用一串特殊的符號,來描述文字長什麼樣子。這在處理大量文件時超級好用。你可以把它想像成一種進階版的搜尋功能。以下整理了最常用的幾組符號。
基礎匹配符號
這些符號用來代表單一個字元或是位置。它們是所有正則表達式的根基。
| 符號 | 說明 | 範例 |
| . | 匹配除了換行以外的任何單一字元 | a.c 可匹配 abc 或 a1c |
| ^ | 匹配字串的開頭 | ^Hello 必須以 Hello 開頭 |
| $ | 匹配字串的結尾 | done$ 必須以 done 結尾 |
| \ | 轉義符號,用來搜尋原本就有特殊意義的符號 | \. 用來搜尋真正的點號 |
| [ ] | 匹配括號內的任一字元 | [aeiou] 匹配任何一個母音 |
| [^ ] | 不匹配括號內的任何字元 | [^0-9] 匹配任何非數字的字元 |
次數與位置的標記
這些符號接在字元後面。用來指定前面的字元應該出現幾次。
| 符號 | 說明 | 範例 |
| * | 出現 0 次或多次 | ab* 可匹配 a, ab, abb |
| + | 出現 1 次或多次 | ab+ 可匹配 ab, abb (不含 a) |
| ? | 出現 0 次或 1 次 | apples? 可匹配 apple 或 apples |
| {n} | 剛好出現 n 次 | \d{3} 匹配 3 個數字 |
| {n,} | 出現至少 n 次 | \d{2,} 匹配 2 個以上的數字 |
| {n,m} | 出現 n 到 m 次 | \d{2,4} 匹配 2 到 4 個數字 |
常用字元群組
為了方便縮寫,正則表達式提供了一些常用的預設符號。這能讓你的規則看起來更簡潔。
| 符號 | 說明 | 同義表達式 |
| \d | 任何數字 | [0-9] |
| \D | 任何非數字 | [^0-9] |
| \w | 數字、英文字母或下底線 | [a-zA-Z0-9_] |
| \s | 任何空白字元 (空格、Tab、換行) | [ \f\n\r\t\v] |
| \S | 任何非空白字元 | [^ \f\n\r\t\v] |
實戰應用範例1
把上面的符號組合起來,就能處理生活中的各種需求。你可以參考下面的例子來練習。
驗證手機號碼 (台灣格式)
^09\d{8}$
解釋:開頭必須是 09,後面接剛好 8 個數字。
簡單的電子郵件格式
\w+@\w+\.\w+
解釋:一串字元接 @,再接一串字元,最後接點號跟一段文字。
移除多餘的空白行
^\s*$
解釋:從開頭到結尾都只有空白或沒內容的行。
正則表達式雖然看起來像外星語。但只要拆開來看,邏輯其實很固定。建議先從最基礎的符號開始試。
實戰應用範例2
你的需求是將 com.app.a 修改為 com.app.b。這裡有一個細節需要注意:你不希望誤改到像是 com.lwfd.apple 這種只是剛好開頭一樣的字串。因此,我們在寫正則表達式時,必須把「邊界」考慮進去。
推薦的正則表達式語法
你可以使用下面的規則來進行精確替換:
搜尋目標: com\.app\.a(?=[.;])|com\.app\.a\b
替換內容: com.app.b
這裡有幾個符號的作用說明:
\.:因為點號在正則中有特殊意義,所以要加反斜線,代表真正的「點」。(?=[.;]):這是一個前瞻斷言,表示後面必須接著分號或點號,但這部分不會被取代掉。\b:代表單字的邊界,確保 a 後面沒有接其他英文字母。
實際操作指令
使用我們之前討論的 Python 腳本,你可以直接在終端機輸入這行指令:
python replace_string.py ./src "com\.app\.a(?=[.;])|com\.app\.a\b" "com.lwfd.b" "*.java"
這個指令會掃描 src 資料夾下所有的 Java 檔案。它會精確地把 com.app.a; 換成 com.app.b;,也會把 com.app.a.abc 換成 com.app.b.abc。
為什麼這樣寫比較安全
如果你只用 com.app.a 當關鍵字,萬一程式碼裡有 com.app.archive,它就會被錯誤地改成 com.app.b rchive,這會導致程式碼壞掉。加上邊界判斷(點號、分號或 \b)可以確保只改到你真正想要變動的部分。
這類替換通常發生在專案重構(Refactor)的時候。如果檔案數量很多,這行指令能幫你省下大約半小時的手動修改時間。