16.正则表达式入门:从日志里找到你要的东西

发布时间:2026/6/26 18:53:18
16.正则表达式入门:从日志里找到你要的东西 一、问题背景100万行日志找到那行ERROR要多久FAB每台设备每天产生海量日志格式如下2026-01-15 08:23:45 [INFO] Lot FAB-ETCH-001 started2026-01-15 08:25:12 [WARN] Pressure spike detected: 52.3 mTorr2026-01-15 08:30:00 [ERROR] Temperature exceeded 85.5°C limit2026-01-15 08:35:22 [INFO] Lot FAB-ETCH-001 completed**工艺工程师要从中找出所有异常事件**。之前怎么做- 用Notepad打开CtrlF搜ERROR- 找到后复制出来手动统计- 然后在Excel里做透视表看趋势**问题**一天100万行只说找到ERROR不难但要**把日志里的时间、设备、参数都提取出来做成表格**手动做2-3小时起步。用正则Regular Expression简称regex的话**3秒出活**。**学完这一篇你能做到**1. 用正则从文本中提取关键信息时间、编号、数值2. 把日志里的数据自动整理成结构化表格3. 写完一次以后相同格式的日志直接复用────────────────────────────────────────二、技术原理先搞懂6个符号很多人觉得正则难是因为一开始背了50个符号。**其实FAB场景下经常用到的就6个**。2.1 最常用的6个元字符| 符号 | 匹配什么 | FAB举例 ||------|---------|---------|| \d | 数字 (0-9) | \d{4} 匹配年份 2026 || \w | 字母数字下划线 | \w 匹配 FAB_ETCH || . | 任意字符换行符除外 | .* 匹配整行内容 || * | 出现0次或多次 | \d* 匹配 数字不出现或出现多次 || | 出现1次或多次 | \d 匹配至少一个数字 || () | 分组提取你需要的部分 | FAB-(\w) 只提取ETCH部分 |2.2 看代码理解import re# 最基础的用法re.search(模式, 文本)# 在文本中找到第一个匹配text Lot FAB-ETCH-001 started# 找数字result re.search(r\d, text)print(result.group()) # 001# 找FAB后面的工艺名result re.search(rFAB-(\w), text)print(result.group(1)) # ETCH只输出分组中的内容# 找Lot ID整体result re.search(r(FAB-\w-\d), text)print(result.group(1)) # FAB-ETCH-001**r 前面的 r 什么意思** raw string——告诉Python字符串里的 \d 是正则表达式符号不是转义字符。不加 r 的话\d 会被Python解释成删除字符。写正则时**永远加 r**。2.3 三个最重要的函数Python的 re 模块中新手只需要记住这3个text ERROR: Temperature85.5°C, Pressure52.3mTorr# 1. search() — 找第一个匹配m re.search(r\d\.?\d*, text) # 找数字含小数点print(m.group()) # 85.5# 2. findall() — 找所有匹配返回列表all_nums re.findall(r\d\.?\d*, text)print(all_nums) # [85.5, 52.3]# 3. finditer() — 找所有匹配返回迭代器可遍历for m in re.finditer(r(\w)(\d\.?\d*), text):print(f参数: {m.group(1)}, 值: {m.group(2)})# 输出: 参数: Temperature, 值: 85.5# 参数: Pressure, 值: 52.3**为什么这样写** \d\.?\d* 的意思是至少一个数字然后可能有小数点小数点后可能还有数字。这个pattern能匹配85.5也能匹配120是提取数值最通用的写法。────────────────────────────────────────三、实战案例一步步写日志解析3.1 第一版提取基本信息import relog 2026-01-15 08:30:00 [ERROR] Temperature exceeded 85.5°C limit# 解析时间 级别 消息pattern r(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w)\] (.)m re.search(pattern, log)if m:time m.group(1) # 2026-01-15 08:30:00level m.group(2) # ERRORmsg m.group(3) # Temperature exceeded 85.5°C limitprint(f{time} | {level} | {msg})**正则解析**(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) 匹配年-月-日 时:分:秒并用括号分组。\[(\w)\] 匹配方括号里的级别名。(.) 匹配剩下的消息文本。3.2 第二版批量处理# 模拟真实的日志数据logs 2026-01-15 08:23:45 [INFO] Lot FAB-ETCH-001 started on chamber_32026-01-15 08:25:12 [WARN] Pressure spike detected: 52.3 mTorr2026-01-15 08:30:00 [ERROR] Temperature exceeded 85.5°C limit2026-01-15 08:35:22 [INFO] Lot FAB-ETCH-001 completed2026-01-15 09:15:30 [ERROR] Alignment failed: 28.0 nm offsetpattern r(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w)\] (.)results []for line in logs.strip().split(\n):m re.search(pattern, line)if m:results.append({time: m.group(1),level: m.group(2),message: m.group(3)})# 统计日志级别levels {}for r in results:lv r[level]levels[lv] levels.get(lv, 0) 1# 找出ERROR日志errors [r for r in results if r[level] ERROR]print(f共 {len(results)} 条日志)print(f级别分布: {levels})print(f错误日志: {len(errors)} 条)for e in errors:print(f ⚠ {e[time]} - {e[message][:40]})3.3 第三版提取数值参数# 从日志中提取所有参数数值对line Temperature85.5°C, Pressure52.3mTorr, Time120s# 提取全部参数名和值pairs re.findall(r(\w)(\d\.?\d*), line)for name, val in pairs:print(f{name}: {val})# 输出# Temperature: 85.5# Pressure: 52.3# Time: 120# 提取带单位的数值values re.findall(r(\d\.?\d*)(°C|mTorr|s|nm), line)for val, unit in values:print(f值{val}, 单位{unit})# 输出# 值85.5, 单位°C# 值52.3, 单位mTorr# 值120, 单位s**为什么这样写** findall 返回的是所有匹配结果的列表每个结果是一个元组 (分组1, 分组2)。利用这个特性一步就能把参数名和值成对提取出来不用写循环以外的复杂逻辑。3.4 封装成函数def parse_log_to_table(text):把原始日志解析成结构化数据参数:text: 多行日志文本返回:list[dict]: 每行日志的解析结果pattern r(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}) \[(\w)\] (.)rows []for line in text.strip().split(\n):m re.search(pattern, line)if not m:continuerows.append({timestamp: m.group(1),level: m.group(2),message: m.group(3),# 顺便提取消息中的数值numbers: re.findall(r\d\.?\d*, m.group(3))})return rows# 使用parsed parse_log_to_table(logs)print(f解析出 {len(parsed)} 行日志)────────────────────────────────────────四、效果对比| 对比维度 | 手工操作NotepadExcel | 正则解析 | 提升 ||---------|--------------------------|---------|------|| 提取100条日志的时间 | 30分钟人工复制粘贴 | 0.5秒 | **3600倍** || 解析1万行日志 | 已崩Excel行数限制 | 3秒出结果 | **无限** || 提取数值参数 | 15分钟一条条复制 | 1行findall搞定 | **不具可比性** || 修改提取规则 | 全部重来 | 改一行pattern就行 | **100倍** || 结果可复用性 | Excel文件换格式就得重做 | 写一次永久复用 | **一劳永逸** |────────────────────────────────────────五、自己动手# 练习题解析设备运行日志import re# 一段真实FAB设备日志device_log 2026-01-20 14:00:00 [INFO] CVD-03 warmup started2026-01-20 14:05:30 [INFO] CVD-03 temperature350.0°C pressure2.5Torr2026-01-20 14:10:15 [INFO] Wafer FAB-CVD-024-W12 loaded to chamber_A2026-01-20 14:15:00 [INFO] Process step1deposition completed in 120s2026-01-20 14:15:30 [WARN] Thickness1252.3Å spec1250±5Å2026-01-20 14:20:00 [ERROR] CVD-03 pressure out of range: 3.8Torr2026-01-20 14:25:00 [INFO] Process aborted, 24 wafers affected# 练习1找出所有ERROR和WARN行用findall# 练习2提取每次运行的时间点和温度值# 练习3统计每台设备(CVD-03)发生了多少次事件# ✏️ 下面写你的代码**思考题**1. 正则匹配的贪婪和非贪婪是什么意思试试 .* 和 .*? 的区别2. 如果日志中有繁体中文正则还能匹配吗试试 [\u4e00-\u9fff] 匹配中文3. 如果日志格式变了比如时间戳变成秒级时间戳你的pattern要改哪里────────────────────────────────────────六、常见误区新手最容易踩的坑| 错误写法 | 问题 | 正确写法 ||---------|------|---------|| \d{2}-\d{2}-\d{4} | 日期格式不对 | \d{4}-\d{2}-\d{2} || [INFO] | 方括号在正则里是特殊字符 | \[INFO\] || .* | 贪婪匹配可能匹配太多 | .*? 非贪婪 || \d.?\d* | 点号会匹配任意字符 | \d\.?\d* 加反斜杠转义 || 不用r字符串 | \d被解释成ASCII转义 | 加 r 前缀 |**调试技巧**用 [regex101.com](https://regex101.com) 在线测试正则表达式。左边写pattern右边写测试文本实时高亮匹配结果比手动猜快10倍。──────────────────────────────────────── **你们FAB的设备日志是什么格式有没有什么特别的pattern需要匹配评论区聊聊** **收藏点赞下一篇讲Excel报表自动化用得上**