正则表达式看起来像一串符号,真正日常用到的其实不多。本文只讲 5 个够用的模式,每个都给出可直接运行的代码和输出说明,帮你把校验、提取、替换和切分这些常见任务写得更短、更稳。
先记住三个最常用的 API:re.match 从字符串开头匹配,re.search 在全文中找第一处,re.findall 返回所有匹配。校验时常用 re.fullmatch,要求整个字符串都符合模式,避免只匹配到一半就误判。
一、邮箱与手机号格式校验
邮箱不必写得过于严苛,日常校验先看基本结构:本地部分、@、域名和后缀。手机号这里以 1 开头、第二位为 3 到 9、后面 9 位数字为例。
import re
email_pattern = r'^\\w.-+@\\w-+\.a-zA-Z{2,}$'
phone_pattern = r'^13-9\d{9}$'
print(bool(re.fullmatch(email_pattern, 'user@example.com')))
print(bool(re.fullmatch(phone_pattern, '13812345678')))
print(bool(re.fullmatch(phone_pattern, '12812345678')))
输出说明:前两个结果是 True,第三个是 False,因为第二位 2 不在 3 到 9 的范围内。注意,这只是格式校验,不能证明邮箱或号码真实存在。
二、用分组提取数字和关键信息
当文本里混着数字时,\d+ 可以找出连续数字;用括号分组,还能把年、月、日这样有结构的信息一次拆开。
import re
text = '订单号 20260115,金额 299 元,分 3 期'
print(re.findall(r'\d+', text))
m = re.search(r'(\d{4})(\d{2})(\d{2})', text)
print(m.groups() if m else None)
输出说明:第一行是 '20260115', '299', '3';第二行是 ('2026', '01', '15'),三个分组分别对应年、月、日。
三、用替换隐藏敏感信息
日志里出现手机号或身份证号时,不要直接原样输出。re.sub 可以把匹配到的部分换成星号,保留前后少量信息便于排查。
import re
log = '用户 13812345678 下单成功'
masked = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', log)
print(masked)
输出说明:结果是"用户 138****5678 下单成功"。这里 \1 和 \2 引用的是前面括号里的两个分组。
四、用分隔符切分不规则字符串
用户输入常混用逗号、分号和空格。先用 re.split 按多种分隔符切分,再去掉空字符串,比反复调用 str.split 更省事。
import re
raw = '苹果,香蕉;橙子 葡萄,,西瓜'
parts = item for item in re.split(r'\[,;;\\s+', raw) if item]
print(parts)
输出说明:结果是 '苹果', '香蕉', '橙子', '葡萄', '西瓜'。字符集里的分号、逗号和空白都被当作分隔符,连续分隔符也不会留下空项。
五、贪婪与非贪婪匹配
默认的 .* 是贪婪的,会尽量多匹配;加上 ? 变成 .*? 后,就会尽量少匹配。取 HTML 标签内容或引号内容时,这个差别最容易看出来。
import re
html = '<p>第一段</p><p>第二段</p>'
print(re.findall(r'<p>.*</p>', html))
print(re.findall(r'<p>.*?</p>', html))
输出说明:贪婪结果是 '\ 第一段\ 第二段\ 第一段\ 第二段\
小结
这 5 个模式覆盖了日常大部分需求:先用 fullmatch 做格式校验,用分组和 findall 提取信息,用 sub 脱敏,用 split 切分,最后用非贪婪匹配控制范围。写正则时先在小例子上验证输出,再放到真实数据里,能少走很多弯路。