re 模块

正则表达式是处理非结构化文本的利器。使用原始字符串 r"..." 避免多重转义。

1. re 核心函数

函数作用返回值
re.search(pattern, string)扫描整个字符串,找到第一个匹配Match 对象或 None
re.match(pattern, string)从字符串开头匹配,相当于 ^Match 对象或 None
re.fullmatch(pattern, string)整个字符串完全匹配模式Match 对象或 None
re.findall(pattern, string)返回所有非重叠匹配的列表(若模式有分组,返回元组列表)list
re.finditer(pattern, string)返回所有匹配的迭代器,产生 Match 对象iterator
re.sub(pattern, repl, string, count=0)替换匹配项,repl 可为函数新字符串
re.subn(pattern, repl, string)同 sub,同时返回替换次数(新字符串, 次数)
re.split(pattern, string, maxsplit=0)按模式分割字符串list
re.compile(pattern, flags)预编译模式,提高反复使用效率Pattern 对象

Match 对象常用方法:

  • group(n):第 n 个分组捕获内容(也就是第几个括号中的内容)(0 为整个匹配)
  • groups():所有分组组成的元组(每个括号中的内容组成的元组)
  • groupdict():命名分组字典
  • start() / end():匹配起始/结束索引
  • span():(start, end)
import re
s = "1a2bd45y93g"
re.match(r"(\d).+(\w)",s),re.match(r"(\d).+(\w)",s).groups(),re.match(r"(\d).+(\w)",s).group(0)
re.match(r"(\d).+(\w)",s).group(2)
(<re.Match object; span=(0, 11), match='1a2bd45y93g'>,
 ('1', 'g'),
 '1a2bd45y93g')
 'g'

2. 模式语法速查

基本字符

  • 大多数字符匹配自身
  • . 匹配除换行符外的任意字符(re.DOTALL 下匹配所有)
  • \ 转义特殊字符,如 \. 匹配句点

字符类

符号含义
[abc]匹配 a、b 或 c 中任一
[^abc]匹配除 a、b、c 外的字符
[a-z]范围
\d数字 [0-9]
\D非数字
\w单词字符 [a-zA-Z0-9_]
\W非单词字符
\s空白字符(空格、制表、换行等)
\S非空白

量词(贪婪默认)

符号次数懒惰形式(尽可能少)
*0 或多次*?
+1 或多次+?
?0 或 1 次??
{n}恰好 n 次{n}?
{n,}至少 n 次{n,}?
{n,m}n 到 m 次{n,m}?

边界/锚点

  • ^ 字符串开头(多行模式下每行开头)
  • $ 字符串结尾(多行模式下每行结尾)
  • \b 单词边界
  • \B 非单词边界

分组与引用

语法含义
( ... )捕获分组,自动编号从 1 开始
(?: ... )非捕获分组,只做逻辑分组不保存
(?P<name> ... )命名捕获分组,可通过 groupdict 或 \g<name> 访问
\n引用第 n 个分组(如 \1)
`(?(id)yesno)`

断言(前瞻/后顾,不消耗字符)

语法含义
(?=...)正向前瞻,后面是…才匹配
(?!...)负向前瞻,后面不是…才匹配
(?<=...)正向后顾,前面是…才匹配(python 要求固定宽度)
(?<!...)负向后顾,前面不是…才匹配

常用标志(可组合)

  • re.I / re.IGNORECASE:忽略大小写
  • re.M / re.MULTILINE:^ $ 匹配每行首尾
  • re.S / re.DOTALL:. 匹配包括换行符
  • re.X / re.VERBOSE:允许模式中添加空白和注释
  • re.A / re.ASCII:\w \b 等仅匹配 ASCII

3. 常见业务场景示例

提取信息

text = "联系方式:张三 (zhangsan@mail.com),电话:13800138000"
# 提取邮箱
email = re.search(r'[\w.-]+@[\w.-]+', text).group()
# 提取手机号(1开头的11位数字)
mobile = re.search(r'1[3-9]\d{9}', text).group()
# 提取所有数字
numbers = re.findall(r'\d+', text)

替换与清洗

# 脱敏手机号中间4位
re.sub(r'(1[3-9]\d)\d{4}(\d{4})', r'\1****\2', '13800138000')  # 138****8000
# 删除多余空白
re.sub(r'\s+', ' ', 'a   b  c').strip()   # 'a b c'
# 将驼峰命名转为下划线
re.sub(r'(?<!^)(?=[A-Z])', '_', 'myVarName').lower()  # 'my_var_name'

验证格式

def is_valid_email(s):
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.fullmatch(pattern, s) is not None

高级分割

# 按逗号分割但忽略引号内的逗号
re.split(r',(?=(?:[^"]*"[^"]*")*[^"]*$)', 'a,"b,c",d')

4. 性能与最佳实践

  • 编译复用:频繁使用相同模式时,用 p = re.compile(r'...'); p.search(s) 更快。
  • 非捕获分组:(?: ) 可减少不必要的捕获开销。
  • 避免“灾难性回溯”:如 (a+)+b 匹配大量 “a” 会指数级耗时,谨慎使用嵌套量词。
  • 原始字符串:始终用 r 前缀,以免 \b 被解释为退格符。