问题与目标
日志、文件名和历史文本常有稳定局部格式,却不是完整 JSON。正则表达式适合按模式提取、校验和替换这类文本。
完成标准:理解字符类、边界、数量、分组和替换,能从日志提取字段,并知道何时应使用 JSON、HTML 或语法解析器。
核心概念
原始字符串 r"..." 可减少 Python 字符串转义与正则转义的冲突。常用结构包括:\d 数字、\s 空白、^/$ 行边界、*/+/{m,n} 数量、(...) 分组。
命名分组 (?P<name>...) 让提取结果更易维护。re.search 在字符串中查找,re.fullmatch 要求整个字符串符合规则,re.sub 执行替换。
re 模块的入口按目标选择:
| 方法 | 目标 |
|---|---|
search | 找到任意位置的第一个匹配 |
match | 只从字符串开头尝试 |
fullmatch | 校验整个字符串 |
finditer | 逐个返回带位置的匹配对象 |
findall | 返回所有匹配内容 |
sub | 替换匹配内容 |
split | 按模式切分 |
捕获组 (...) 会进入结果,纯粹用于组合时可写 (?:...)。\b 表示单词边界,| 表示选择,\1 或 (?P=name) 可以引用前面捕获的内容。
可运行实现
python
import re
LOG_PATTERN = re.compile(
r"^(?P<date>\d{4}-\d{2}-\d{2}) "
r"(?P<level>INFO|WARNING|ERROR) "
r"user=(?P<user>[a-zA-Z0-9_-]+) "
r"latency=(?P<latency>\d+)ms$"
)
def parse_log(line: str) -> dict[str, str | int] | None:
match = LOG_PATTERN.fullmatch(line.strip())
if match is None:
return None
data = match.groupdict()
return {
"date": data["date"],
"level": data["level"],
"user": data["user"],
"latency_ms": int(data["latency"]),
}
lines = [
"2026-08-25 INFO user=alice latency=18ms",
"invalid line",
]
for line in lines:
print(parse_log(line))
secret = "token=abc123xyz"
print(re.sub(r"(?<=token=)[^\s]+", "***", secret))
输出一条结构化字典、一个 None,以及脱敏后的 token=***。真实清洗任务应统计无法匹配的行,不能静默丢弃。
再用一组小实验观察查找、切分和回调替换:
python
import re
text = "ERROR id=12; WARNING id=37; ERROR id=51"
print(re.findall(r"(?:ERROR|WARNING) id=(\d+)", text))
print(re.split(r";\s*", text))
masked = re.sub(
r"id=(\d+)",
lambda match: f"id={'*' * len(match.group(1))}",
text,
)
print(masked)
业务校验要区分“格式看起来正确”和“值在业务上有效”。正则可以检查日期形状 YYYY-MM-DD,但日期是否真实存在应交给日期解析器。
常见问题与排查
.匹配过多:它表示几乎任意字符,能写明确字符类时不要滥用.*。- 贪婪匹配跨过目标边界:使用更明确的终止条件,必要时才用
*?。 match、search、fullmatch选错:校验完整字段优先fullmatch。- 正则变得难以阅读:使用预编译、命名分组和测试样例拆分规则。
- 用正则解析任意嵌套 JSON/HTML:嵌套和转义会迅速失控,应使用对应解析器。
- 把简化邮箱或手机号模式当成全球通用规则:格式规则会变化,应根据明确业务范围校验,并保留更新入口。
小结
正则适合稳定、局部、半结构化的文本规则。可维护的模式应有明确边界、命名字段、失败统计和覆盖正常与异常输入的测试。
#Python
#大模型
#AI
License: CC BY-NC 4.0
Updated 3 hours ago
Was this article helpful? Give it a like.
0 comments


