正则表达式(Regular Expression,简称 Regex)是一种用于匹配、查找、替换文本中的字符串模式的工具。Python 通过内置的re模块支持正则表达式。
一、常用功能
| 功能 | 说明 |
|---|
| 模式(Pattern) | 用于描述匹配规则的字符串 |
| 匹配(Match) | 检查字符串是否符合模式 |
| 搜索(Search) | 在字符串中查找匹配的子串 |
| 替换(Replace) | 将匹配的内容替换为其他字符串 |
二、常用函数
| 函数 | 作用 | 返回值 |
|---|
re.match(pattern, string) | 从字符串开头匹配 | Match对象或None |
re.search(pattern, string) | 全文搜索第一个匹配 | Match对象或None |
re.findall(pattern, string) | 查找所有匹配,返回列表 | 列表 |
re.finditer(pattern, string) | 查找所有匹配,返回迭代器 | 迭代器 |
re.sub(pattern, repl, string) | 替换所有匹配 | 新字符串 |
re.split(pattern, string) | 按模式分割字符串 | 列表 |
re.compile(pattern) | 编译模式(提高效率) | Pattern对象 |
三、基础语法
1. 字面字符
import re # 直接匹配普通字符 pattern = "hello" text = "hello world" print(re.match(pattern, text)) # <re.Match object> print(re.match("hi", text)) # None
2. 元字符
| 元字符 | 含义 | 示例 |
|---|
. | 匹配任意字符(除换行符) | a.c匹配abc |
^ | 匹配字符串开头 | ^hello |
$ | 匹配字符串结尾 | world$ |
* | 匹配 0 次或多次 | a*匹配"","a","aa" |
+ | 匹配 1 次或多次 | a+匹配"a","aa" |
? | 匹配 0 次或 1 次 | a?匹配"","a" |
{n} | 匹配正好 n 次 | a{3}匹配"aaa" |
{n,} | 匹配至少 n 次 | a{2,}匹配"aa","aaa" |
{n,m} | 匹配 n 到 m 次 | a{2,4}匹配"aa","aaa","aaaa" |
| | 或(选择) | cat|dog匹配cat或dog |
() | 分组 | (ab)+匹配ab,abab |
[] | 字符集 | [aeiou]匹配元音字母 |
[^] | 否定字符集 | [^0-9]匹配非数字 |
\ | 转义 | \.匹配. |
3. 字符类
| 字符类 | 含义 | 等价于 |
|---|
\d | 数字 | [0-9] |
\D | 非数字 | [^0-9] |
\w | 单词字符(字母、数字、下划线) | [a-zA-Z0-9_] |
\W | 非单词字符 | [^a-zA-Z0-9_] |
\s | 空白字符(空格、制表符、换行) | [ \t\n\r\f\v] |
\S | 非空白字符 | [^ \t\n\r\f\v] |
\b | 单词边界 | \bword\b |
\B | 非单词边界 |
四、常用匹配模式
1. 匹配数字
import re # 整数 re.match(r'\d+', '123abc') # '123' # 浮点数 re.search(r'\d+\.\d+', 'pi=3.14') # '3.14' # 负数 re.search(r'-?\d+', '温度-5度') # '-5'
2. 匹配邮箱
email_pattern = r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}' text = '联系我: user@example.com' print(re.search(email_pattern, text).group()) # user@example.com
3. 匹配手机号(中国)
phone_pattern = r'1[3-9]\d{9}' text = '我的电话是13812345678' print(re.search(phone_pattern, text).group()) # 13812345678
五、分组与捕获
1. 基本分组
import re # 使用括号分组 pattern = r'(\d{4})-(\d{2})-(\d{2})' text = '日期: 2024-01-15' match = re.search(pattern, text) if match: print(match.group(0)) # 2024-01-15(完整匹配) print(match.group(1)) # 2024(第一组) print(match.group(2)) # 01(第二组) print(match.group(3)) # 15(第三组) print(match.groups()) # ('2024', '01', '15')
2. 命名分组
pattern = r'(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})' text = '日期: 2024-01-15' match = re.search(pattern, text) if match: print(match.group('year')) # 2024 print(match.group('month')) # 01 print(match.group('day')) # 15
3. 非捕获分组
# 使用 (?:...) 不捕获分组 pattern = r'(?:\d{4})-(?:\d{2})-(?:\d{2})' text = '日期: 2024-01-15' # 匹配但不会保存分组
六、贪婪与非贪婪匹配
| 模式 | 行为 | 示例 |
|---|
.* | 贪婪(尽可能多匹配) | .*匹配整个字符串 |
.*? | 非贪婪(尽可能少匹配) | .*?匹配最小长度 |
import re text = '<h1>标题</h1><p>段落</p>' # 贪婪匹配:尽量多匹配 print(re.search(r'<.*>', text).group()) # <h1>标题</h1><p>段落</p> # 非贪婪匹配:尽量少匹配 print(re.search(r'<.*?>', text).group()) # <h1>
七、替换与分割
1. 替换
import re text = '我的电话是13812345678,他的电话是13987654321' # 替换所有匹配 result = re.sub(r'\d{11}', '****', text) print(result) # 我的电话是****,他的电话是**** # 使用回调函数替换 def hide_phone(match): return match.group()[:3] + '****' + match.group()[-4:] result = re.sub(r'(\d{11})', hide_phone, text) print(result) # 我的电话是138****5678,他的电话是139****4321
2. 分割
import re text = '苹果,香蕉;橘子 葡萄' # 按多个分隔符分割 result = re.split(r'[,; ]+', text) print(result) # ['苹果', '香蕉', '橘子', '葡萄']
八、编译正则表达式
import re # 编译模式(提高效率) pattern = re.compile(r'\d{3}-\d{4}-\d{4}') text = '电话: 010-1234-5678' print(pattern.search(text).group()) # 010-1234-5678 # 预编译后可以反复使用 phones = ['010-1234-5678', '020-8765-4321', 'invalid'] for phone in phones: if pattern.match(phone): print(f'有效: {phone}')
常用
| 函数 | 匹配位置 | 返回 | 适用场景 |
|---|
re.match() | 开头 | Match或None | 检查字符串开头 |
re.search() | 全文 | Match或None | 查找第一个匹配 |
re.findall() | 全文 | 列表 | 获取所有匹配 |
re.finditer() | 全文 | 迭代器 | 遍历所有匹配 |
re.sub() | 全文 | 字符串 | 替换所有匹配 |
re.split() | 全文 | 列表 | 按模式分割 |