Python 正则表达式完全指南:从基础语法到实战案例
正则表达式(Regular Expression)是处理字符串匹配、提取、替换的强大工具,在数据清洗、表单验证、文本分析等场景中应用广泛。本文基于 Python 的 re
模块,结合基础语法与实战案例,带你系统掌握正则表达式的使用方法。
一、正则表达式基础语法
正则表达式的核心是 “匹配模式”,通过特定符号组合定义规则,匹配符合条件的字符串。以下是常用语法分类总结:
1. 精确匹配与选择匹配
- 精确匹配:直接写目标字符串,匹配完全一致的内容。
示例:red
仅匹配字符串 "red"。 - 选择匹配:用
|
分隔多个选项,匹配任意一个选项。
示例:red|yellow|blue
匹配 "red"、"yellow" 或 "blue"。
2. 模糊匹配(字符集与元字符)
当需要匹配 “某一类字符” 时,使用字符集或元字符(元字符是字符集的简化写法)。
(1)字符集 [ ]
[abc]
:匹配 "a"、"b"、"c" 中的任意一个字符。[^abc]
:匹配除 "a"、"b"、"c" 以外的任意字符(^
表示 “非”)。[0-9]
:匹配 0-9 中的任意一个数字。[a-z]
/[A-Z]
:匹配小写 / 大写英文字母。[A-z]
:匹配英文字母(含大小写)或下划线_
(注意:ASCII 表中Z
与a
之间有特殊字符,实际推荐用[a-zA-Z_]
)。[\u4e00-\u9fa5]
:匹配任意一个中文汉字(Python 支持 Unicode 编码)。
(2)元字符
元字符是字符集的 “简写形式”,更简洁高效:
元字符 | 含义 | 等价字符集 | |
---|---|---|---|
\d | 匹配数字 | [0-9] | |
\D | 匹配非数字 | [^0-9] | |
\w | 匹配字母、数字、下划线 | [a-zA-Z0-9_] | |
\W | 匹配非字母、数字、下划线 | [^a-zA-Z0-9_] | |
. | 匹配除换行符 \n 外的任意字符 | - | |
`\d | \D` | 匹配任意字符(包括换行符) | - |
3. 量词:控制匹配次数
量词用于定义 “前面的字符 / 表达式需要匹配多少次”,解决 “重复匹配” 问题:
量词 | 含义 | 示例 |
---|---|---|
re{n} | 匹配 re 恰好 n 次 | \d{3} 匹配 3 位数字(如 "123") |
re{n,} | 匹配 re 至少 n 次 | \d{2,} 匹配 2 位及以上数字(如 "12"、"123") |
re{n,m} | 匹配 re 至少 n 次、最多 m 次 | \d{2,4} 匹配 2-4 位数字(如 "12"、"1234") |
re? | 匹配 re 0 次或 1 次(可选) | ab? 匹配 "a" 或 "ab" |
re+ | 匹配 re 1 次或多次 | \d+ 匹配 1 位及以上数字 |
re* | 匹配 re 0 次或多次 | a* 匹配 ""、"a"、"aa" 等 |
贪婪匹配与非贪婪匹配
- 贪婪匹配:默认行为,尽可能多匹配(“能多不少”)。
示例:\d{2,4}
匹配 "12345" 时,会优先匹配 4 位数字 "1234"。 - 非贪婪匹配:在量词后加
?
,尽可能少匹配(“能少不多”)。
示例:\d{2,4}?
匹配 "12345" 时,会优先匹配 2 位数字 "12"。
4. 限定符:锚定匹配位置
限定符用于定义 “匹配的字符串必须在什么位置”,常见的有:
^
:匹配字符串的开头。
示例:^abc
仅匹配以 "abc" 开头的字符串(如 "abc123",不匹配 "123abc")。$
:匹配字符串的结尾。
示例:abc$
仅匹配以 "abc" 结尾的字符串(如 "123abc",不匹配 "abc123")。^abc$
:精确匹配整个字符串(只能是 "abc",长度和内容完全一致)。
5. 分组:提取与复用匹配结果
用 ()
对正则表达式分组,可实现 “提取子结果” 和 “复用匹配规则”。
(1)普通分组
每个 ()
对应一个分组,分组索引从 1 开始(0 是整个匹配结果)。
示例:(\d{2})([a-z]+)
匹配 "12ab" 时,分组 1 是 "12",分组 2 是 "ab"。
(2)命名捕获分组
用 (?P<name>re)
给分组命名,后续可通过名称获取结果(更易读)。
示例:(?P<year>\d{4})-(?P<month>\d{2})
匹配 "2024-05" 时,可通过 "year" 获取 "2024","month" 获取 "05"。
(3)非捕获分组
用 (?:re)
取消分组的 “捕获功能”(仅用于分组匹配,不单独提取结果)。
示例:(?:abc)|(?:def)
匹配 "abc" 或 "def",但不单独捕获分组结果。
(4)反向引用
用 \n
(n 是分组索引)复用前面分组的匹配结果,常用于匹配 “重复模式”。
示例:
(.)(.)\1\2
匹配 "ABAB" 类型(如 "abab"、"1212")。(.)\1(.)\2
匹配 "AABB" 类型(如 "aabb"、"1122")。
6. 断言:有条件的匹配
断言是 “附加条件的匹配”,不消耗字符,仅判断条件是否满足(也叫 “零宽断言”)。
断言类型 | 语法 | 含义 | 示例 |
---|---|---|---|
正向确定断言 | re(?=rex) | 匹配后面是 rex 的 re | \d+(?=px) 匹配 "12px" 中的 "12" |
正向否定断言 | re(?!rex) | 匹配后面不是 rex 的 re | \d+(?!px) 匹配 "12cm" 中的 "12" |
反向确定断言 | (?<=rex)re | 匹配前面是 rex 的 re | (?<=¥)\d+ 匹配 "¥100" 中的 "100" |
反向否定断言 | (?<!rex)re | 匹配前面不是 rex 的 re | (?<!¥)\d+ 匹配 "$100" 中的 "100" |
7. 经典案例:密码强度验证
需求:密码必须包含数字、大小写字母、特殊符号(!@#$%^&*
),长度 8-18 位。
正则表达式:^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*]).{8,18}$
解析:
(?=.*[0-9])
:确保包含至少一个数字。(?=.*[a-z])
:确保包含至少一个小写字母。(?=.*[A-Z])
:确保包含至少一个大写字母。(?=.*[!@#$%^&*])
:确保包含至少一个特殊符号。.{8,18}
:匹配 8-18 位任意字符(除换行符)。^
和$
:锚定整个字符串,避免前后有多余字符。
二、Python re
模块核心方法
Python 的 re
模块提供了正则表达式的核心操作,以下是常用方法的详解与示例。
1. match(pattern, string, flags=0)
- 功能:从字符串开头匹配,若开头不匹配则返回
None
,匹配成功返回Match
对象。 - 参数:
pattern
:正则表达式(字符串或编译后的对象)。string
:待匹配的字符串。flags
:匹配模式(如re.I
忽略大小写,re.S
让.
匹配换行符)。
示例:
import re# 命名捕获分组示例
res = re.match(r'(?P<first>\d{2})(?P<second>\d{2})', '1234ab')
print(res.span()) # 返回匹配区间 (0, 4)(匹配了前4个字符 "1234")
print(res.groups()) # 返回所有分组元组 ('12', '34')
print(res.group()) # 返回整个匹配结果 '1234'
print(res.group(1)) # 返回第1个分组结果 '12'
print(res.groupdict()) # 返回命名分组字典 {'first': '12', 'second': '34'}
2. fullmatch(pattern, string, flags=0)
- 功能:匹配整个字符串(从开头到结尾),完全符合正则才返回
Match
对象,否则返回None
。 - 场景:用于严格验证(如手机号、身份证号)。
示例:
import re# 验证手机号(11位数字)
res = re.fullmatch(r'\d{11}', '12345678903abc')
print(res) # None(字符串末尾有 "abc",不满足11位数字)res = re.fullmatch(r'\d{11}', '12345678903')
print(res) # <re.Match object; span=(0, 11), match='12345678903'>(匹配成功)
3. findall(pattern, string, flags=0)
- 功能:查找字符串中所有符合正则的子串,返回列表(无匹配则返回空列表)。
- 分组影响:
- 无分组:返回所有匹配结果的列表。
- 1 个分组:返回仅包含分组结果的列表。
- 多个分组:返回列表,每个元素是分组结果的元组。
示例:
import re# 多个分组:提取数字+字母组合
res = re.findall(r'(\d+)([a-z]+)', 'ab12cd34ef')
print(res) # [('12', 'cd'), ('34', 'ef')](每个元组是一组数字+字母)# 无分组:提取所有数字
res = re.findall(r'\d+', 'ab12cd34ef')
print(res) # ['12', '34']
4. search(pattern, string, flags=0)
- 功能:在字符串中任意位置查找第一个符合正则的子串,返回
Match
对象(无匹配则返回None
)。 - 区别于
match
:match
仅从开头匹配,search
可匹配任意位置。
示例:
import re# 查找第一个数字+字母组合
res = re.search(r'(\d+)([a-z]+)', 'ab12cd34ef')
print(res.group()) # '12cd'(整个匹配结果)
print(res.groups()) # ('12', 'cd')(分组结果)
5. sub(pattern, repl, string, count=0, flags=0)
- 功能:替换字符串中符合正则的子串,返回替换后的新字符串。
- 参数:
repl
:替换后的内容(字符串或函数)。count
:替换次数(0 表示替换所有,默认 0)。
- 分组引用:在
repl
中用\n
(n 是分组索引)引用分组结果。
示例:
import re# 替换所有数字+字母组合为 "中"
res = re.sub(r'\d+[a-z]+', '中', '12cd34ab')
print(res) # '中中'# 手机号脱敏:13623456789 → 136****6789
res = re.sub(r'(\d{3})\d{4}(\d{4})', r'\1****\2', '13623456789')
print(res) # '136****6789'(\1 引用前3位,\2 引用后4位)# 限制替换次数(仅替换1次)
res = re.sub(r'\d+', '中', '12cd34ab', count=1)
print(res) # '中cd34ab'
6. subn(pattern, repl, string, count=0, flags=0)
- 功能:与
sub
类似,但返回元组(替换后的字符串, 替换次数)
。
示例:
import reres = re.subn(r'\d+', '中', '12cd34ab')
print(res) # ('中cd中ab', 2)(替换后的字符串 + 替换了2次)
三、实战:任务清单表单验证
结合正则表达式与 re
模块,实现任务清单中的表单验证功能(如手机号、邮箱、任务名长度):
import redef validate_phone(phone):"""验证手机号(11位数字)"""pattern = r'^\d{11}$'return bool(re.fullmatch(pattern, phone))def validate_email(email):"""验证邮箱(如 xxx@xxx.com)"""pattern = r'^\w+@\w+(\.[a-zA-Z]{2,3}){1,2}$'return bool(re.fullmatch(pattern, email))def validate_task_name(name):"""验证任务名(1-50位字符,不包含特殊符号)"""pattern = r'^[a-zA-Z0-9\u4e00-\u9fa5]{1,50}$'return bool(re.fullmatch(pattern, name))# 测试
print(validate_phone('13623456789')) # True
print(validate_email('test@163.com')) # True
print(validate_task_name('学习正则表达式!')) # False(包含特殊符号 "!")
四、常见问题与注意事项
- 转义字符问题:Python 字符串中的
\
需要转义(如\d
需写为r'\d'
或'\\d'
),推荐用 原始字符串r''
避免转义麻烦。 - 匹配模式
flags
:re.I
:忽略大小写(如re.match(r'abc', 'ABC', re.I)
匹配成功)。re.S
:让.
匹配换行符(默认不匹配)。re.M
:多行模式(让^
/$
匹配每行的开头 / 结尾)。
- 性能优化:频繁使用的正则表达式,用
re.compile(pattern)
编译为对象,可提高执行效率。