正则表达式(Regex)是用一段"模式字符串"在文本中查找、提取、替换内容的技术。学会它,处理日志、校验输入、批量替换的效率会提升一个量级。
1. 三个基础概念
| 概念 | 写法 | 匹配示例 |
|---|---|---|
| 字符类 | [abc]、[0-9]、\d | \d 匹配任意数字 |
| 量词 | * + ? {n,m} | \d{3,4} 匹配 3~4 位数字 |
| 锚点 | ^ 开头、$ 结尾 | ^abc$ 整串必须是 abc |
2. 常用元字符
. 任意字符(换行除外)
\d 数字 \w 字母数字下划线
\s 空白 \b 单词边界
[^] 取反 | 或(如 cat|dog)
() 分组 (?:) 非捕获分组
3. Python 中的用法
import re
text = "联系我: 138-1234-5678 或 010-87654321"
# 查找所有手机号(11 位,可带分隔符)
phones = re.findall(r"1[3-9]\d[- ]?\d{4}[- ]?\d{4}", text)
print(phones) # ['138-1234-5678']
# 提取邮箱
email = "hello.world@example.com"
m = re.search(r"([\w.]+)@([\w.]+)", email)
print(m.group(1), m.group(2)) # hello.world example.com
# 替换: 脱敏手机号中间四位
masked = re.sub(r"(1[3-9]\d)\d{4}(\d{4})", r"\1****\2", text)
print(masked) # 联系我: 138-****-5678 或 010-87654321
在 Python 中写正则强烈建议使用原始字符串(r"..."),避免反斜杠转义地狱。
4. 必背实战模板
手机号: ^1[3-9]\d{9}$
邮箱: ^[\w.+-]+@[\w-]+(\.[\w-]+)+$
IP 地址: ^(\d{1,3}\.){3}\d{1,3}$ (简单版)
URL: ^https?://[\w.-]+(/[\w./?%&=-]*)?$
日期: ^\d{4}-\d{2}-\d{2}$
5. 贪婪与懒惰
html = "<b>bold</b> and <b>strong</b>"
# 贪婪 .* 会匹配到最后一个 >
print(re.findall(r"<b>.*</b>", html))
# ['<b>bold</b> and <b>strong</b>']
# 懒惰 .*? 只匹配到第一个 >
print(re.findall(r"<b>.*?</b>", html))
# ['<b>bold</b>', '<b>strong</b>']
6. 实战:解析访问日志
把前面学的串起来,解析一行常见的 Web 访问日志:
import re
log = '203.0.113.7 - - [04/Aug/2026:12:00:01 +0800] "GET /index.html HTTP/1.1" 200 5120'
pattern = (
r"(\d+\.\d+\.\d+\.\d+)" # IP
r".*?\[(.*?)\]" # 时间
r'.*?"(\w+) (/[^"]*)"' # 方法 + 路径
r"\s(\d{3})" # 状态码
)
m = re.match(pattern, log)
if m:
ip, time, method, path, status = m.groups()
print(ip, time, method, path, status)
# 203.0.113.7 04/Aug/2026:12:00:01 +0800 GET /index.html 200
7. 性能陷阱:灾难性回溯
嵌套量词会让引擎疯狂回溯,导致 CPU 飙到 100%。经典案例 (a+)+$ 匹配 aaaaX 会指数级爆炸。对策:避免嵌套量词、给量词加限定,Python 3.11+ 还可以设超时兜底。
import re
# Python 3.11+ 可以给正则设超时,防卡死
pattern = re.compile(r"(a+)+$", re.TIMEOUT)
try:
pattern.match("a" * 30 + "X")
except re.TimeoutError:
print("正则超时了——典型灾难性回溯!")
💡 练习建议:regex101.com 支持实时高亮匹配与解释,是学习正则的最佳 playground。记住"先用最简单的模式跑通,再逐步加复杂规则"。