
本文介绍如何用 Python 的 re 模块(启用多行模式)设计稳健的正则表达式,从分隔符为19个等号的三行头日志中,准确捕获时间摘要标题与后续多行正文内容,并避免常见捕获组覆盖问题。
本文介绍如何用 python 的 `re` 模块(启用多行模式)设计稳健的正则表达式,从分隔符为19个等号的三行头日志中,准确捕获时间摘要标题与后续多行正文内容,并避免常见捕获组覆盖问题。
在解析结构化程度较低但具有固定分隔模式的日志文件时,正则表达式仍是高效且轻量的选择。本例中,日志采用「19个等号 → 时间摘要行 → 19个等号 → 空行 → 多行正文 → 下一组分隔符」的循环结构。关键挑战在于:既要精确界定每个记录的边界,又要完整捕获跨行正文内容,同时避免因重复捕获组(如 (.*)+)导致仅保留最后一行的陷阱。
✅ 推荐正则表达式(多行模式下)
import re
pattern = r'^={19}\n(?!={19}$)(.+)\n={19}((?:\n(?!={19}$).*)*)'
log_content = """===================
2024-05-20 14:23:18 - User login failed
===================
Invalid credentials for user 'admin'.
Attempt from IP: 192.168.1.105.
Session ID: sess_7a8b9c
===================
2024-05-20 14:25:02 - Database connection timeout
===================
Failed to connect to primary DB (host: db-prod.internal).
Retry count: 3. Last error: 'Connection refused'.
"""
# 启用 MULTILINE 模式:使 ^ 和 $ 匹配每行起止
matches = re.findall(pattern, log_content, re.M)
for i, (header, body) in enumerate(matches, 1):
print(f"Record{i}Field1:\n{header.strip()}")
print(f"Record{i}Field2:\n{body.strip()}\n")输出示例:
Record1Field1: 2024-05-20 14:23:18 - User login failed Record1Field2: Invalid credentials for user 'admin'. Attempt from IP: 192.168.1.105. Session ID: sess_7a8b9c Record2Field1: 2024-05-20 14:25:02 - Database connection timeout Record2Field2: Failed to connect to primary DB (host: db-prod.internal). Retry count: 3. Last error: 'Connection refused'.
? 表达式逐段解析
| 片段 | 说明 |
|---|---|
| ^={19}\n | 行首匹配 19 个 = 后跟换行(^ 在 re.M 下匹配每行开头) |
| (?!={19}$)(.+) | 标题行:负向先行断言确保该行 不是 19 个 =,再捕获非空内容 |
| \n={19} | 紧接其后的第二行分隔符(换行 + 19 个 =) |
| ((?:\n(?!={19}$).*)*) | 正文块:非捕获组 (?:...) 重复匹配「换行 + 非分隔符行」,避免捕获组覆盖;* 可匹配零行或多行正文 |
⚠️ 注意事项:
- 必须传入 re.M(re.MULTILINE)标志,否则 ^/$ 仅匹配全文首尾;
- 不推荐使用 .* 贪婪匹配正文(如原尝试中的 (\n.*)+),它会吞掉后续分隔符并导致边界错位;
- 若正文可能为空,可将末尾 * 改为 *?(惰性)或额外处理空值逻辑;
- 实际生产中建议配合 re.compile() 预编译提升性能,并添加 re.DOTALL(若需匹配含换行的单字段)——但本例中已通过显式 \n 控制更安全。
✅ 后续处理建议
提取出 (header, body) 元组后,可轻松映射为结构化数据:
records = [
{"timestamp_summary": h.split(" - ", 1)[0].strip(),
"summary": h.split(" - ", 1)[1].strip() if " - " in h else "",
"content": b.strip()}
for h, b in matches
]
# 直接写入 SQLite / Pandas DataFrame / JSONL 文件等该方案兼顾准确性、可读性与可维护性,适用于日志预处理、ETL 清洗及轻量级数据库导入场景。

















