正则表达式
本教程共 70 篇 · 第 51 篇 · 更新于 2026-07-22 · 约 5 分钟阅读
51. 正则表达式
本节目标:掌握
re模块的基本用法,理解常用正则符号的含义,能写出匹配、搜索、替换的正则表达式。
正则表达式(Regular Expression,简称 regex)是一种描述文本模式的微型语言。它用一系列特殊符号定义「什么样的字符串符合条件」,在数据验证、文本提取、格式化等场景非常有用。
Python 通过 re 模块支持正则表达式。
基础匹配
import re
# 匹配字符串开头
result = re.match(r'hello', 'hello world')
print(result) # <re.Match object; span=(0, 5), match='hello'>
print(result.group()) # hello
# 匹配失败返回 None
print(re.match(r'world', 'hello world')) # None
re.match() 从字符串开头开始匹配。如果模式不在开头,返回 None。
Tip正则字符串前面加
r(raw string),让反斜杠不被 Python 转义。写正则时始终用r'...',这是好习惯。
常用元字符
| 符号 | 含义 |
|---|---|
. | 任意单个字符(除换行) |
\d | 数字 [0-9] |
\w | 单词字符 [a-zA-Z0-9_] |
\s | 空白字符(空格、制表符、换行等) |
\b | 单词边界 |
^ | 字符串开头 |
$ | 字符串结尾 |
* | 前一个字符出现 0 次或多次 |
+ | 前一个字符出现 1 次或多次 |
? | 前一个字符出现 0 次或 1 次 |
{n} | 前一个字符恰好出现 n 次 |
{n,m} | 前一个字符出现 n 到 m 次 |
| | 或 |
() | 分组 |
import re
print(re.match(r'\d+', '123abc').group()) # 123
print(re.match(r'\w+', 'hello_world').group()) # hello_world
print(re.match(r'a*b', 'aaab').group()) # aaab
print(re.match(r'colou?r', 'color').group()) # color
三种匹配方法的区别
| 函数 | 行为 |
|---|---|
re.match() | 从字符串开头匹配 |
re.search() | 扫描整个字符串,返回第一个匹配 |
re.findall() | 返回所有匹配组成的列表 |
re.finditer() | 返回所有匹配的迭代器 |
text = 'The price is $25 and $30'
print(re.match(r'\$\d+', text)) # None($ 不在开头)
print(re.search(r'\$\d+', text).group()) # $25
print(re.findall(r'\$\d+', text)) # ['$25', '$30']
Note日常用得最多的是
re.search()和re.findall()。match()只在明确需要「从开头匹配」时使用,比如验证用户输入的格式。
分组提取
用括号 () 把模式分成组,可以单独提取:
import re
text = 'Name: Alice, Age: 25'
pattern = r'Name: (\w+), Age: (\d+)'
m = re.search(pattern, text)
print(m.group(0)) # 整个匹配:Name: Alice, Age: 25
print(m.group(1)) # 第一组:Alice
print(m.group(2)) # 第二组:25
给组起名字,代码更易读:
pattern = r'Name: (?P<name>\w+), Age: (?P<age>\d+)'
m = re.search(pattern, text)
print(m.group('name')) # Alice
print(m.group('age')) # 25
替换文本:re.sub()
import re
text = 'The color is red, I like red'
result = re.sub(r'red', 'blue', text)
print(result) # The color is blue, I like blue
# 限制替换次数
result = re.sub(r'red', 'blue', text, count=1)
print(result) # The color is blue, I like red
替换时可以用函数动态生成结果:
def double(m):
num = int(m.group())
return str(num * 2)
print(re.sub(r'\d+', double, '1 2 3')) # 2 4 6
贪婪与非贪婪
正则默认是「贪婪」模式:尽可能匹配更多字符。
text = '<div>content</div>'
print(re.search(r'<.*>', text).group()) # <div>content</div>(贪婪)
print(re.search(r'<.*?>', text).group()) # <div>(非贪婪)
在量词后加 ? 变成非贪婪模式,匹配最少字符。
Warning贪婪非贪婪选不对,是正则 bug 的高发区。写完后多测几个边界 case,尤其是标签、引号成对出现的情况。
编译正则:re.compile()
同一个正则表达式多次使用时,先编译能提升性能:
import re
email_pattern = re.compile(r'^[\w.-]+@[\w.-]+\.\w+$')
print(email_pattern.match('alice@example.com'))
print(email_pattern.match('bad-email'))
编译后的对象有 match()、search()、findall()、sub() 等方法,和 re 模块的函数一一对应。
常见正则模式
import re
# 邮箱(简化版)
email = r'^[\w.-]+@[\w.-]+\.\w+$'
# 手机号(中国大陆)
phone = r'^1[3-9]\d{9}$'
# 身份证号(18 位)
idcard = r'^\d{17}[\dXx]$'
# IP 地址(简化版)
ip = r'^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$'
# 验证
def validate(pattern, text):
return bool(re.match(pattern, text))
print(validate(phone, '13800138000')) # True
print(validate(phone, '12345678901')) # False
Note正则表达式不是万能的。复杂的规则(比如邮箱的完整 RFC 规范)用正则表示会非常冗长。实际项目中,「够用即可」的简化版往往比 100% 准确的冗长版更实用。
小结
re.match()从开头匹配,re.search()全局找第一个,re.findall()找全部。()分组提取,(?P<name>...)命名分组。re.sub()替换文本,支持函数回调。- 量词默认贪婪,加
?变非贪婪。 - 多次使用的正则先
compile(),性能更好。
正则表达式像一门浓缩的外语,符号密集,初学时看着头疼。但一旦掌握,处理字符串的效率会提升一个量级。不需要背下所有符号,记住最常用的十几个,遇到复杂模式再查文档。
来源:参考了 runoob「Python3 正则表达式」、liaoxuefeng「正则表达式」、pythondoc「re 模块」等,改写后所得。