Python3 模式匹配:从基础到高级的匹配技巧 模式匹配是 Python 中处理数据结构和文本的重要技术,从简单的字符串匹配到复杂的结构化数据匹配都有广泛应用。Python 3 提供了多种模式匹配工具,包括基础的字符串方法、re 模块的正则表达式,以及 Python 3.10 引入的结构化模式匹配(match-case 语句)。本文将系统介绍这些技术,帮助你高效处理各类匹配场景。
基础字符串模式匹配 Python 字符串内置了多种方法,可直接用于简单的模式匹配需求,无需引入额外模块。
1. 子串检查(包含性匹配)
in 运算符:检查子串是否存在于字符串中
str.find(sub):返回子串首次出现的索引(未找到返回 -1)
str.count(sub):统计子串出现的次数
1 2 3 4 5 6 7 8 9 10 11 12 13 s = "hello world, hello python" print("hello" in s) print("java" in s) print(s.find("hello" )) print(s.find("hello" , 5 )) print(s.count("hello" )) print(s.count("l" ))
2. 前缀 / 后缀匹配
str.startswith(prefix):检查字符串是否以指定前缀开头
str.endswith(suffix):检查字符串是否以指定后缀结尾
1 2 3 4 5 6 7 8 9 10 filename = "document.txt" url = "https://example.com" print(filename.startswith("doc" )) print(url.startswith(("http://" , "https://" ))) print(filename.endswith(".txt" )) print(filename.endswith((".doc" , ".pdf" )))
正则表达式:复杂文本模式匹配 对于更复杂的模式(如邮箱验证、手机号提取、格式化字符串解析等),需要使用 Python 内置的 re 模块(正则表达式)。正则表达式通过 “模式字符串” 定义匹配规则,支持通配符、重复、分组等高级特性。
1. 正则表达式基础语法
元字符
描述
示例
.
匹配任意单个字符(除换行符)
a.b 匹配 “aab”、”acb” 等
*
匹配前一个字符 0 次或多次
ab* 匹配 “a”、”ab”、”abb” 等
+
匹配前一个字符 1 次或多次
ab+ 匹配 “ab”、”abb” 等(不匹配 “a”)
?
匹配前一个字符 0 次或 1 次
ab? 匹配 “a”、”ab”
^
匹配字符串开头
^hello 匹配以 “hello” 开头的字符串
$$`
匹配字符串结尾
`world$$ 匹配以 “world” 结尾的字符串
[]
匹配括号内的任意一个字符
[abc] 匹配 “a”、”b” 或 “c”
[^]
匹配不在括号内的任意字符
[^abc] 匹配除 “a”、”b”、”c” 外的字符
()
分组,将部分模式视为一个整体
(ab)+ 匹配 “ab”、”abab” 等
\d
匹配任意数字(等价于 [0-9])
\d{3} 匹配 3 位数字
\D
匹配非数字(等价于 [^0-9])
\w
匹配字母、数字或下划线(等价于 [a-zA-Z0-9_])
\w+ 匹配单词
\W
匹配非单词字符
\s
匹配空白字符(空格、制表符、换行符等)
\S
匹配非空白字符
{n}
匹配前一个字符恰好 n 次
a{3} 匹配 “aaa”
{n,}
匹配前一个字符至少 n 次
a{2,} 匹配 “aa”、”aaa” 等
{n,m}
匹配前一个字符 n 到 m 次
a{1,3} 匹配 “a”、”aa”、”aaa”
2. re 模块核心函数
函数
描述
re.match(pattern, string)
从字符串开头匹配模式(仅匹配开头)
re.search(pattern, string)
在整个字符串中搜索第一个匹配项
re.findall(pattern, string)
查找所有匹配项,返回列表
re.finditer(pattern, string)
查找所有匹配项,返回迭代器(含匹配对象)
re.sub(pattern, repl, string)
替换所有匹配项为 repl
re.split(pattern, string)
按匹配项分割字符串
3. 常用正则匹配场景示例 场景 1:验证邮箱格式 1 2 3 4 5 6 7 8 9 10 import redef 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("test@example.com" )) print(is_valid_email("invalid-email.com" )) print(is_valid_email("user.name+tag@domain.co.uk" ))
场景 2:提取文本中的所有手机号 1 2 3 4 5 6 7 8 import retext = "联系我们:13812345678,或拨打400-800-8888,也可联系13987654321" pattern = r"1\d{10}|400-\d{3}-\d{4}" phones = re.findall(pattern, text) print(phones)
场景 3:替换文本中的敏感词 1 2 3 4 5 6 7 8 9 10 11 import retext = "这个产品太垃圾了,简直是废物!" sensitive_words = ["垃圾" , "废物" ] pattern = re.compile(r"|" .join(sensitive_words), re.IGNORECASE) censored_text = pattern.sub("***" , text) print(censored_text)
场景 4:解析 URL 中的参数 1 2 3 4 5 6 7 8 import reurl = "https://example.com/search?query=python&page=2&sort=desc" pattern = r"(\w+)=(\w+)" params = re.findall(pattern, url) print(dict(params))
结构化模式匹配(Python 3.10+) Python 3.10 引入了 match-case 语句,支持对数据结构 (如列表、元组、字典、对象)进行模式匹配,类似于其他语言的 switch-case,但功能更强大。
1. 基础语法 1 2 3 4 5 6 7 match 变量: case 模式1 : case 模式2 : case _:
2. 常见结构化匹配场景 场景 1:匹配字面量和变量 1 2 3 4 5 6 7 8 9 10 11 12 13 def handle_command (command ): match command: case "start" : print("启动程序" ) case "stop" : print("停止程序" ) case "restart" : print("重启程序" ) case other: print(f"未知命令:{other} " ) handle_command("start" ) handle_command("pause" )
场景 2:匹配序列(列表 / 元组) 1 2 3 4 5 6 7 8 9 10 11 12 def process_data (data ): match data: case [1 , 2 , x]: print(f"匹配成功,第三个元素是:{x} " ) case ( "user" , name, age ): print(f"用户信息:姓名={name} ,年龄={age} " ) case _: print("未匹配的结构" ) process_data([1 , 2 , 3 ]) process_data(("user" , "Alice" , 25 )) process_data([1 , 3 , 5 ])
场景 3:匹配字典(键值对) 1 2 3 4 5 6 7 8 9 10 11 def handle_user (user ): match user: case {"name" : name, "age" : age} if age >= 18 : print(f"成年用户:{name} ({age} 岁)" ) case {"name" : name, "age" : age}: print(f"未成年用户:{name} ({age} 岁)" ) case _: print("无效的用户数据" ) handle_user({"name" : "Bob" , "age" : 20 }) handle_user({"name" : "Charlie" , "age" : 15 })
场景 4:匹配类对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class Point : def __init__ (self, x, y ): self.x = x self.y = y def describe_point (point ): match point: case Point(0 , 0 ): print("这是原点" ) case Point(x, 0 ): print(f"这是x轴上的点:x={x} " ) case Point(0 , y): print(f"这是y轴上的点:y={y} " ) case Point(x, y): print(f"这是普通点:({x} , {y} )" ) describe_point(Point(0 , 0 )) describe_point(Point(5 , 0 )) describe_point(Point(3 , 4 ))
场景 5:组合模式与通配符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def parse_expression (expr ): match expr: case ["add" , a, b]: return a + b case ["multiply" , a, b]: return a * b case ["power" , base, 2 ]: return base **2 case ["power" , base, exp]: return base** exp case _: raise ValueError("未知表达式" ) print(parse_expression(["add" , 2 , 3 ])) print(parse_expression(["multiply" , 4 , 5 ])) print(parse_expression(["power" , 3 , 2 ])) print(parse_expression(["power" , 2 , 5 ]))
三种模式匹配技术的对比与选择
技术
适用场景
优势
局限性
字符串内置方法
简单子串检查、前缀 / 后缀匹配
无需额外模块,直观高效
不支持复杂模式(如通配符、重复)
正则表达式(re 模块)
复杂文本匹配(邮箱、手机号、日志解析等)
支持强大的模式定义,适合文本处理
语法较复杂,性能对复杂模式可能较差
结构化模式匹配(match-case)
数据结构匹配(列表、字典、对象等)
支持结构化数据,语法清晰,支持条件匹配
仅 Python 3.10+ 支持,不适合文本匹配
实战案例:日志分析工具 结合正则表达式和字符串方法,实现一个简单的日志分析工具,提取错误日志并统计频率:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import refrom collections import defaultdictdef analyze_error_logs (log_text ): error_pattern = r"\[(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\] ERROR: (.*)" errors = re.findall(error_pattern, log_text) if not errors: print("未发现错误日志" ) return error_counts = defaultdict(int) for time, msg in errors: error_counts[msg] += 1 print(f"共发现 {len(errors)} 条错误日志:" ) for msg, count in error_counts.items(): print(f"- {msg} (出现 {count} 次)" ) log_text = """ [2023-10-01 08:30:00] INFO: 程序启动 [2023-10-01 08:30:05] ERROR: 数据库连接失败 [2023-10-01 08:30:10] ERROR: 数据库连接失败 [2023-10-01 08:30:15] INFO: 重试连接 [2023-10-01 08:30:20] ERROR: 权限不足 """ analyze_error_logs(log_text)
运行结果 :
1 2 3 共发现 3 条错误日志: - 数据库连接失败(出现 2 次) - 权限不足(出现 1 次)
v1.3.10