平常寫程式或做作業常要翻 log 檔案。檔案太大時根本看不完。這段 Python 腳本可以幫上忙。它像是一個客製化的 grep 工具。支援關鍵字高亮顯示。還能決定要看關鍵字前後幾行內容。這對分析程式報錯很有幫助。
如何開始使用
下載程式碼:
https://github.com/max32002/MaxFontScripts/blob/master/grep.py
確保你的電腦已經安裝了 Python 3 環境。你可以透過終端機或命令提示字元來執行它。
基本指令格式
python grep.py 關鍵字 路徑
你可以加上這些參數:
- -b 數字:顯示關鍵字前面幾行。
- -a 數字:顯示關鍵字後面幾行。
- -i:忽略英文字母大小寫。
- -l:把找到的關鍵字標上顏色。
- -E:開啟正規表示法搜尋模式。
- -ext .txt:搜尋指定副檔名。
- -o 檔名:將搜尋結果存成檔案。
- -r or -R:預設只會掃描該層資料夾,除非你加上 -r 才會遞迴搜尋子目錄。
實際操作範例
假設要找 logs 資料夾內所有包含 ERROR 的行。並且要看錯誤發生的前 2 行與後 2 行。還要標記顏色。
python grep.py ERROR ./logs -b 2 -a 2 -l
如果要用正規表示法找特定格式。例如找 IP 位址。並限制只找 .txt 檔案。
python grep.py "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" ./data -E -ext .txt
如果想把搜尋結果存起來。方便之後寫報告用。
python grep.py "Login Failed" auth.log -o result.txt
這套工具邏輯很單純。不用安裝複雜的套件。做實驗數據分析或是 debug 都很實用。
正規表示式(Regular Expression)在處理文字時非常強大。以下整理了最常用的規則與符號,不論是在 Python、JavaScript 或是終端機工具都通用。
基本字元與邊界
這些符號用來定位文字的位置或是匹配特定類型的單一字元。
| 符號 | 說明 | 範例 |
| . | 匹配除換行符號外的任何單一字元 | a.c 可匹配 abc, a2c |
| ^ | 匹配字串的開頭 | ^Hello 必須以 Hello 開頭 |
| $ | 匹配字串的結尾 | done$ 必須以 done 結尾 |
| \d | 匹配任何數字,等同於 [0-9] | \d\d 匹配兩位數 |
| \D | 匹配任何非數字字元 | \D 匹配字母或符號 |
| \w | 匹配字母、數字或底線 | \w+ 匹配一個單字 |
| \s | 匹配任何空白字元(空格、Tab、換行) | \s+ 匹配連續空白 |
| \b | 匹配單字邊界 | \bcat\b 只匹配 cat 不含 category |
量詞(次數匹配)
用來決定前面的字元可以連續出現幾次。
- *:出現 0 次或多次。
- +:出現 1 次或多次(至少要有一個)。
- ?:出現 0 次或 1 次(選用性質)。
- {n}:精確出現 n 次。
- {n,}:出現至少 n 次。
- {n,m}:出現 n 到 m 次之間。
字元集合與群組
當你需要指定一段範圍或是將多個規則組合在一起時。
- [abc]:匹配括號內的任一字元。
- [^abc]:匹配除了 abc 以外的任何字元。
- [a-z]:匹配小寫字母 A 到 Z。
- [A-Z]:匹配大寫字母 A 到 Z。
- |:邏輯「或」(OR),例如
cat|dog匹配 cat 或 dog。 - (…):擷取群組,將規則組合在一起,之後可以用
\1或在程式中提取。 - (?:…):非擷取群組,只組合不記錄內容,效能較好。
貪婪與懶惰匹配
這是進階使用時最常遇到的陷阱。
預設情況下,量詞是「貪婪的」,會盡可能匹配最長的字串。例如對於 <div>test</div> 使用 <.*> 會匹配到整個字串。
如果在量詞後面加上問號(例如 *? 或 +?),會變成「懶惰模式」,只匹配到第一個符合條件的結尾。例如 <.*?> 只會匹配到 <div>。
實戰小筆記
在撰寫規則時,如果遇到特殊符號如 .、*、?、( 等,必須在前面加上反斜線 \ 進行跳脫,才能匹配符號本身。
例如要匹配一個 IP 地址,簡單的寫法會是:\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}。
你想看如何將這些規則應用在你之前的 versionName 修改腳本中嗎?
非擷取群組 (?:...) 的主要作用是「只組合、不存檔」。它讓你可以對一組字元進行量詞操作,但不會在記憶體中記錄這個群組的內容,這在處理複雜字串或提升效能時很有用。
範例一:純粹為了使用量詞
如果你想匹配「連續出現多次的單字」,但你只關心整個字串,不需要單獨取出那個單字。
- 正規表示式:
^(?:https?|ftp)://[^\s]+$ - 說明:這裡用
(?:https?|ftp)把通訊協定組合起來,後面加個|代表「或」。如果你用(https?|ftp),程式會額外幫你存下一個變數(Group 1)記錄到底是匹配到 http 還是 ftp。用非擷取群組則可以省去這個開銷。
範例二:搭配擷取群組使用
當你的正規表示式很長,裡面有很多層括號,使用非擷取群組可以讓你的「編號」更乾淨。
- 待處理文字:
ID: 123-ABC, ID: 456-DEF - 正規表示式:
ID: (\d+)-(?:[A-Z]+) - 程式結果:
Group 1會拿到123。- 因為
[A-Z]+放在(?:...)裡面,它不會被分配到Group 2。 - 這在寫程式時,可以避免去算到底現在是第幾個括號。
範例三:在分割字串時的差異 (以 Python 為例)
這是在實作中最明顯的區別。
Python
import re
text = "apple123orange456banana"
# 使用一般群組:分隔符號會被保留在結果清單中
print(re.split(r"(\d+)", text))
# 輸出: ['apple', '123', 'orange', '456', 'banana']
# 使用非擷取群組:分隔符號會被丟棄,只留下分割後的內容
print(re.split(r"(?:\d+)", text))
# 輸出: ['apple', 'orange', 'banana']
總結建議
當你發現括號只是為了「要把這幾個字看成一體」或是「為了用 OR 邏輯」,而不是為了之後要把這段文字抽出來用時,就應該習慣加上 ?:。這不僅能讓程式跑得快一點,也能讓後續維護程式碼的人(或你自己)知道,這一段內容不需要被抓取。