Python 的正则表达式主要通过 re 模块实现,用于字符串的匹配、查找、替换、分割等操作。以下是系统的用法讲解,包含核心概念、常用函数、语法规则和实战示例。
一、核心前置知识
正则表达式:一种描述字符串模式的语法,用于匹配 / 提取符合规则的字符串片段。
re 模块:Python 内置的正则处理模块,需先导入:
import re。原始字符串:正则中建议使用
r'pattern'(原始字符串),避免反斜杠\被 Python 转义(如r'\d'比'\\d'更简洁)。
二、常用正则语法规则(核心)
三、re 模块核心函数
1. re.match ():从字符串开头匹配
语法:
re.match(pattern, string, flags=0)返回:匹配对象(成功)/ None(失败)
常用方法:
group()(获取匹配内容)、span()(获取匹配位置)
import re
# 匹配开头的 "python"
result = re.match(r'python', 'python123')
if result:
print(result.group()) # 输出:python
print(result.span()) # 输出:(0, 6)
# 开头不匹配,返回 None
result2 = re.match(r'python', '123python')
print(result2) # 输出:None
2. re.search ():在字符串任意位置匹配(仅第一个)
语法:
re.search(pattern, string, flags=0)返回:匹配对象(成功)/ None(失败)
# 任意位置匹配 "python"
result = re.search(r'python', '123python456')
if result:
print(result.group()) # 输出:python
print(result.span()) # 输出:(3, 9)
3. re.findall ():匹配所有符合规则的子串,返回列表
语法:
re.findall(pattern, string, flags=0)返回:列表(无匹配则返回空列表)
# 提取所有数字
result = re.findall(r'\d+', 'abc123def456')
print(result) # 输出:['123', '456']
# 提取所有邮箱(简单匹配)
result2 = re.findall(r'\w+@\w+\.\w+', '邮箱1:test@163.com,邮箱2:abc@qq.com')
print(result2) # 输出:['test@163.com', 'abc@qq.com']
4. re.sub ():替换匹配的子串
语法:
re.sub(pattern, repl, string, count=0, flags=0)参数:
repl为替换后的字符串,count为替换次数(0 表示全部)返回:替换后的新字符串
# 替换所有数字为 "*"
result = re.sub(r'\d+', '*', '手机号:13812345678')
print(result) # 输出:手机号:*
# 只替换前2个数字段
result2 = re.sub(r'\d+', '*', '123abc456def789', count=2)
print(result2) # 输出:*abc*def789
5. re.split ():按匹配的子串分割字符串
语法:
re.split(pattern, string, maxsplit=0, flags=0)参数:
maxsplit为最大分割次数(0 表示全部)返回:分割后的列表
# 按逗号/空格分割字符串
result = re.split(r'[, ]+', 'a,b c d')
print(result) # 输出:['a', 'b', 'c', 'd']
# 最多分割2次
result2 = re.split(r'[, ]+', 'a,b c d', maxsplit=2)
print(result2) # 输出:['a', 'b', 'c d']
6. re.compile ():预编译正则表达式(提升多次匹配效率)
语法:
pattern = re.compile(pattern, flags=0)用途:多次使用同一正则时,预编译可减少重复解析开销
# 预编译正则
phone_pattern = re.compile(r'1[3-9]\d{9}') # 匹配手机号
# 多次使用编译后的正则
result1 = phone_pattern.search('手机号:13812345678')
result2 = phone_pattern.findall('13987654321 12345678901')
print(result1.group()) # 输出:13812345678
print(result2) # 输出:['13987654321']
四、常用 flags(匹配模式)
示例:
# 忽略大小写匹配
result = re.match(r'python', 'Python123', re.I)
print(result.group()) # 输出:Python
# 多行模式匹配每行开头的数字
text = '1. abc\n2. def\n3. ghi'
result = re.findall(r'^\d', text, re.M)
print(result) # 输出:['1', '2', '3']
五、分组与反向引用
1. 分组提取(()`)
通过 group(n) 获取第 n 个分组(group(0) 是整个匹配内容,group(1) 是第一个分组,依此类推)。
# 提取姓名和年龄
text = '姓名:张三,年龄:25'
result = re.search(r'姓名:(.*),年龄:(\d+)', text)
if result:
print(result.group(0)) # 输出:姓名:张三,年龄:25
print(result.group(1)) # 输出:张三
print(result.group(2)) # 输出:25
2. 反向引用(\n 或 \g<n>)
在正则中引用已匹配的分组,或在替换时使用 \n 引用。
# 匹配重复的字符(如 "aa"、"bb")
result = re.findall(r'(\w)\1', 'aabbcc1122')
print(result) # 输出:['a', 'b', 'c', '1', '2']
# 替换:将 "姓名:张三" 转为 "张三(姓名)"
text = '姓名:张三'
result = re.sub(r'姓名:(.*)', r'\1(姓名)', text)
print(result) # 输出:张三(姓名)
六、实战示例
示例 1:验证手机号
def is_phone(phone):
pattern = re.compile(r'^1[3-9]\d{9}$')
return bool(pattern.match(phone))
print(is_phone('13812345678')) # True
print(is_phone('12345678901')) # False
示例 2:提取 HTML 中的链接
html = '<a href="https://www.baidu.com">百度</a><a href="https://www.python.org">Python</a>'
links = re.findall(r'href="(.*?)"', html)
print(links) # 输出:['https://www.baidu.com', 'https://www.python.org']
示例 3:清理字符串中的特殊字符
text = ' 这是一段包含@#¥%的文本 123... '
# 去除特殊字符、数字和首尾空格
clean_text = re.sub(r'[^\u4e00-\u9fa5\s]', '', text).strip()
print(clean_text) # 输出:这是一段包含的文本
七、注意事项
贪婪匹配 vs 非贪婪匹配:
默认是贪婪匹配(尽可能多匹配):
r'\d+'匹配123会全部匹配;非贪婪匹配(加
?):r'\d+?'匹配123只会匹配1。
转义字符:正则中的特殊字符(如
.、*、()需用\转义,或放在[]中(如[.]匹配.)。性能:复杂正则或大量文本匹配时,优先用
re.compile()预编译,避免重复解析。边界处理:匹配手机号、邮箱等时,务必用
^和$限定开头结尾,避免部分匹配(如138123456789被误判为手机号)。
评论