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)yes no)`
断言(前瞻/后顾,不消耗字符)
语法 含义 (?=...)正向前瞻,后面是…才匹配 (?!...)负向前瞻,后面不是…才匹配 (?<=...)正向后顾,前面是…才匹配(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 被解释为退格符。