Python3 正则表达式
正则表达式(Regular Expression)是一种用于匹配、查找和处理字符串的强大工具,通过特殊符号(元字符)定义匹配规则,广泛应用于文本检索、数据清洗、格式验证等场景。Python3 通过内置的
二、Python
1.
2.
3.
4.
5.
6.
7.
1. 基础分组:
2. 命名分组:
re模块提供了完整的正则表达式支持,本文从基础语法到实战案例,全面解析 Python 正则表达式的使用。
一、正则表达式基础:元字符与匹配规则
正则表达式的核心是 “元字符”—— 具有特殊含义的符号,用于描述字符的模式。掌握这些元字符是使用正则的基础。
1. 常用元字符(核心!必须掌握)
| 元字符 | 含义 | 示例 |
|---|---|---|
. |
匹配任意单个字符(除换行符\n) |
a.b 匹配 "aab"、"acb",不匹配 "ab" |
* |
匹配前面的字符 / 子模式0 次或多次(贪婪匹配) | ab* 匹配 "a"、"ab"、"abb"、"abbb" |
+ |
匹配前面的字符 / 子模式1 次或多次 | ab+ 匹配 "ab"、"abb",不匹配 "a" |
? |
匹配前面的字符 / 子模式0 次或 1 次 | ab? 匹配 "a"、"ab",不匹配 "abb" |
^ |
匹配字符串开头(若在 [] 中则表示 “非”) | ^abc 匹配 "abc123",不匹配 "xabc" |
$ |
匹配字符串结尾 | abc$ 匹配 "123abc",不匹配 "abcx" |
[] |
字符集,匹配其中任意一个字符(可指定范围) | [abc] 匹配 "a"、"b"、"c";[0-9] 匹配任意数字 |
() |
分组,将子模式视为一个整体,可用于提取或重复 | (ab)+ 匹配 "ab"、"abab" |
| |
逻辑 “或”,匹配左边或右边的模式 | a|b 匹配 "a" 或 "b" |
\d |
匹配任意数字(等价于[0-9]) |
\d{3} 匹配 "123"、"456" |
\D |
匹配非数字(等价于[^0-9]) |
\D 匹配 "a"、"!"、" " |
\w |
匹配字母、数字、下划线(等价于[a-zA-Z0-9_]) |
\w+ 匹配 "hello"、"user123" |
\W |
匹配非字母、数字、下划线(等价于[^a-zA-Z0-9_]) |
\W 匹配 "!"、"@"、" " |
\s |
匹配空白字符(空格、制表符\t、换行符\n等) |
a\sb 匹配 "a b"、"a\tb" |
\S |
匹配非空白字符 | a\Sb 匹配 "aab"、"a@b" |
\b |
单词边界(匹配单词开头或结尾,不匹配具体字符) | \bhello\b 匹配 "hello",不匹配 "helloworld" |
2. 量词:指定匹配次数
除了
*/+/?,还可以用{m,n}精确指定匹配次数:| 量词 | 含义 | 示例 |
|---|---|---|
{n} |
匹配恰好 n 次 | a{3} 匹配 "aaa" |
{n,} |
匹配至少 n 次 | a{2,} 匹配 "aa"、"aaa"、"aaaa" |
{n,m} |
匹配n 到 m 次(包含 n 和 m) | a{1,3} 匹配 "a"、"aa"、"aaa" |
3. 贪婪匹配与非贪婪匹配
- 贪婪匹配(默认):尽可能匹配最长的符合规则的字符串(如
*/+/{n,m}默认贪婪)。 - 非贪婪匹配:在量词后加
?,尽可能匹配最短的符合规则的字符串。
示例:
import re
text = "aabbaabb"
# 贪婪匹配:.*会匹配从第一个a到最后一个b的最长字符串
print(re.match("a.*b", text).group()) # 输出:aabbaabb
# 非贪婪匹配:.*?会匹配从第一个a到最近的b的最短字符串
print(re.match("a.*?b", text).group()) # 输出:aabb
二、Python re模块:正则表达式的 “操作工具”
re模块提供了一系列函数,用于实现正则表达式的匹配、查找、替换等操作,核心函数如下:1. re.match(pattern, string):从字符串开头匹配
- 若匹配成功,返回
Match对象;否则返回None。 - 注意:仅从字符串第一个字符开始匹配,不匹配则返回
None(哪怕中间有符合规则的子串)。
import re
# 匹配以"hello"开头的字符串
result = re.match("hello", "hello world")
print(result.group()) # 输出:hello(匹配成功)
# 不匹配(字符串开头不是"hello")
result = re.match("hello", "hi hello")
print(result) # 输出:None
2. re.search(pattern, string):在字符串任意位置查找第一个匹配
- 扫描整个字符串,返回第一个符合规则的
Match对象;无匹配则返回None。 - 与
match的区别:search不限制从开头匹配。
import re
# 在任意位置查找第一个"world"
result = re.search("world", "hello world, welcome to the world")
print(result.group()) # 输出:world(只返回第一个匹配)
3. re.findall(pattern, string):查找所有匹配的子串
- 返回一个列表,包含所有符合规则的子串(无匹配则返回空列表)。
import re
# 查找所有数字
text = "age: 25, score: 90, weight: 65"
numbers = re.findall(r"\d+", text) # r前缀表示原始字符串,避免转义问题
print(numbers) # 输出:['25', '90', '65']
4. re.finditer(pattern, string):查找所有匹配,返回迭代器
- 与
findall类似,但返回Match对象的迭代器(适合处理大量匹配结果,节省内存)。
import re
text = "a:1, b:2, c:3"
# 查找所有"字母:数字"格式的子串
iter_result = re.finditer(r"(\w):(\d)", text)
for match in iter_result:
print(match.group()) # 输出:a:1、b:2、c:3
print(f"字母:{match.group(1)}, 数字:{match.group(2)}") # 提取分组内容
5. re.sub(pattern, repl, string):替换匹配的子串
- 将字符串中所有符合规则的子串替换为
repl(可以是字符串或函数),返回替换后的新字符串。
示例:
import re
# 将所有数字替换为"*"
text = "密码:123456,验证码:654321"
new_text = re.sub(r"\d+", "*", text)
print(new_text) # 输出:密码:*,验证码:*
# 用函数动态替换(将数字加1)
def add_one(match):
return str(int(match.group()) + 1)
text = "a:1, b:2"
new_text = re.sub(r"\d+", add_one, text)
print(new_text) # 输出:a:2, b:3
6. re.split(pattern, string):按匹配的子串分割字符串
- 以符合规则的子串为分隔符,将字符串分割成列表。
import re
# 按逗号或空格分割
text = "apple, banana orange; grape"
parts = re.split(r"[,; ]", text) # 匹配逗号、分号或空格
print(parts) # 输出:['apple', '', 'banana', 'orange', '', 'grape']
7. re.compile(pattern):编译正则表达式(提高效率)
- 将正则表达式字符串编译为
RegexObject对象,可重复使用(多次调用时效率更高)。
示例:
import re
# 编译正则(只做一次)
pattern = re.compile(r"\d+")
# 重复使用编译后的对象
text1 = "score: 90"
text2 = "age: 25"
print(pattern.findall(text1)) # ['90']
print(pattern.findall(text2)) # ['25']
三、分组与捕获:提取特定内容
通过
()定义分组,可以从匹配结果中提取特定部分,这是正则的核心应用之一。1. 基础分组:group()与groups()
match.group(n):返回第 n 个分组的内容(n=0 表示整个匹配,n=1 开始是分组)。match.groups():返回所有分组内容的元组。
示例:
import re
text = "张三, 年龄:25, 性别:男"
# 分组匹配:姓名、年龄、性别
pattern = r"(\w+), 年龄:(\d+), 性别:(\w+)"
match = re.search(pattern, text)
print(match.group(0)) # 整个匹配:张三, 年龄:25, 性别:男
print(match.group(1)) # 第1组(姓名):张三
print(match.group(2)) # 第2组(年龄):25
print(match.groups()) # 所有分组:('张三', '25', '男')
2. 命名分组:(?P<name>pattern)(更易读)
给分组命名,通过
group("name")提取,避免记索引。 import re
text = "邮箱: user@example.com"
# 命名分组:用户名(name)和域名(domain)
pattern = r"邮箱: (?P<name>\w+)@(?P<domain>\w+\.\w+)"
match = re.search(pattern, text)
print(match.group("name")) # user
print(match.group("domain")) # example.com
四、实战案例:正则表达式的典型应用
1. 验证邮箱格式
import re
def is_valid_email(email):
# 邮箱规则:用户名@域名(域名含.和字母)
pattern = r"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$"
return re.match(pattern, email) is not None
print(is_valid_email("user@example.com")) # True
print(is_valid_email("user.name+tag@example.co.uk")) # True
print(is_valid_email("invalid-email")) # False
2. 提取 URL 中的域名
import re
url = "https://www.example.com/path?query=123"
# 匹配域名(www.xxx.com 或 xxx.com)
pattern = r"https?://(www\.)?([a-zA-Z0-9-]+\.[a-zA-Z]+)"
match = re.search(pattern, url)
print(match.group(2)) # example.com
3. 清洗文本中的特殊字符
import re
text = "这是一段包含【特殊字符】、<标签>和\n换行的文本!"
# 移除所有非中文字符、字母、数字和空格
clean_text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9 ]", "", text)
print(clean_text) # 这是一段包含特殊字符和换行的文本
五、避坑指南(新手常犯错误)
-
忘记
^和$导致部分匹配:
验证格式时(如手机号),若不加^和$,可能匹配到包含目标模式的长字符串。
错误示例:re.match(r"\d{11}", "13800138000abc")会返回匹配(实际想验证 11 位纯数字)。
正确做法:re.match(r"^\d{11}$", "13800138000")(确保整个字符串都是 11 位数字)。 -
转义字符处理不当:
正则中\是转义符(如\d表示数字),但 Python 字符串中\也是转义符,需用r前缀定义 “原始字符串” 避免冲突。
错误示例:re.match("\d+", "123")(Python 会将\d解析为转义符,实际应写成r"\d+")。
正确做法:re.match(r"\d+", "123")。 -
贪婪匹配导致结果不符合预期:
例如提取 HTML 标签<div>内容</div>,用<.*>会匹配整个<div>内容</div>(贪婪),而想要匹配<div>需用非贪婪模式<.*?>。 -
过度依赖正则处理复杂场景:
正则适合简单的文本匹配,复杂场景(如 HTML/XML 解析)建议用专用库(如BeautifulSoup),避免正则逻辑过于复杂难以维护。
六、常用正则模板(直接复用)
| 场景 | 正则表达式(Python 格式) |
|---|---|
| 手机号 | r"^1[3-9]\d{9}$" |
| 身份证号 | r"^\d{17}[\dXx]$" |
| 邮箱 | r"^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" |
| 整数 / 小数 | r"^-?\d+(\.\d+)?$" |
| URL | r"^https?://[^\s]+$" |
| 中文 | r"[\u4e00-\u9fa5]" |
总结
Python 正则表达式的核心是
re模块和元字符系统:- 元字符定义匹配规则(如
\d匹配数字,*匹配多次); re模块函数实现具体操作(match/search查找,findall提取,sub替换);- 分组功能用于精准提取特定内容,命名分组提高可读性;
- 实际使用中需注意贪婪 / 非贪婪匹配、转义字符和边界匹配。
掌握正则表达式能极大提升文本处理效率,建议结合实际场景多练习,逐步熟悉各种元字符的组合用法
浙公网安备 33010602011771号