日誌與多行文字
日誌一行一筆時,用 re.M 讓 ^ 對齊行首。訊息跨很多行時,用 re.S 讓 . 吃換行,或明確寫 \n。
抽出 ERROR 行
import re
log = """
2026-09-15 10:01:02 INFO started
2026-09-15 10:01:03 ERROR disk full
2026-09-15 10:01:04 INFO retry
2026-09-15 10:01:05 ERROR timeout
"""
LINE = re.compile(
r"^(?P<ts>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) (?P<level>ERROR) (?P<msg>.*)$",
re.MULTILINE,
)
for m in LINE.finditer(log):
print(m["ts"], m["msg"])
簡易 combined log(Nginx / Apache 常見形狀)
import re
line = (
'203.0.113.10 - - [15/Sep/2026:10:19:00 +0800] '
'"GET /regex HTTP/1.1" 200 1234'
)
ACCESS = re.compile(
r"""
^(?P<ip>\S+)
\s+\S+\s+\S+\s+
\[(?P<time>[^\]]+)\]
\s+"(?P<method>\S+)\s+(?P<path>\S+)\s+(?P<proto>[^"]+)"
\s+(?P<status>\d{3})
\s+(?P<size>\S+)
""",
re.VERBOSE,
)
m = ACCESS.search(line)
print(m.groupdict() if m else "parse failed")
正式環境用專門的 log parser 或先 split 再對時間戳用一小段 regex。這條示範「空白分欄 + 方括號時間 + 引號請求列」。
跨行區塊
import re
trace = """
TRACE begin
detail line 1
detail line 2
TRACE end
noise
"""
block = re.search(
r"TRACE begin.*?TRACE end",
trace,
flags=re.DOTALL,
)
print(block.group(0) if block else None)
沒有 re.S 時,. 遇換行就停,begin 與 end 不在同一行就匹配不到。.*? 懶惰,避免一次吃到檔案最後一個 TRACE end。
切段落
import re
doc = "第一段。\n\n第二段還有內容。\n\n\n第三段。"
parts = [p.strip() for p in re.split(r"\n\s*\n", doc) if p.strip()]
print(parts)
相關資料
- 旗標:compile 與旗標
- 錨點:錨點與邊界
- 影音:Google 課裡的 Baby Names 練習也是「從半結構化文字抽欄位」,見 官方影音