目录

Python正则表达式

Python:正则表达式

正则表达式的基础和应用

一、正则表达式核心语法(四大基石)

1. ​ 元字符(特殊符号)​
  • 定位符 ^ :匹配字符串 开始位置 $ :匹配字符串 结束位置 \b :匹配 单词边界 ​(如 \bword\b 匹配独立单词)
  • 字符类 . :任意单个字符(默认不包括换行符) \d :数字(等价 [0-9]\w :字母、数字、下划线(等价 [a-zA-Z0-9_]\s :空白符(空格、Tab、换行等)
  • 转义符 \ :将特殊字符转为普通字符(如 `` 匹配真正的点号)
2. ​ 量词(重复次数)​
  • * :0次或多次
  • + :1次或多次
  • ? :0次或1次
  • {n} :精确n次
  • {n,} :至少n次
  • {n,m} :n到m次
3. ​ 字符集合与逻辑
  • [abc] :匹配a、b、c中的任意一个
  • [a-z] :匹配小写字母a到z
  • [^abc] :否定集合(匹配不在abc中的字符)
  • | :逻辑或(如 cat|dog 匹配"cat"或"dog")
4. ​ 分组与引用
  • ( ) :捕获分组(可通过 \1$1 反向引用)
  • (?: ) :非捕获分组(仅用于逻辑分组)
  • (?P) :命名分组(Python中可通过名称引用)

二、正则引擎工作原理(NFA vs DFA)

1. ​ NFA引擎(主流实现)​
  • 特点 :支持回溯、捕获组、零宽断言等高级功能,但存在性能风险
  • 匹配流程
  1. 从起始位置尝试匹配
  2. 记录所有可能的分支(回溯点)
  3. 失败时退回最近回溯点继续尝试
  4. 直到匹配成功或完全失败
2. ​ DFA引擎
  • 特点 :无回溯,线性时间复杂度,但功能受限(不支持分组引用)
  • 流程 :一次性扫描文本,无状态回退

三、关键应用场景与解决方案

1. ​ 数据验证(精准匹配)​
  • 邮箱验证
^[\w-]+@([\w-]+)+[\w-]{2,4}$
  • ^$ 确保整行匹配
  • [\w-]+ 允许用户名包含字母、数字、点、减号
  • ([\w-]+)+ 匹配多级域名(如 “mail.” 或 “google.com.")
  • [\w-]{2,4} 匹配顶级域名(如 com、org)
  • 强密码规则
^(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{8,}$
  • (?=.*\d) :正向预查确保包含数字
  • (?=.*[a-z]) :必须有小写字母
  • (?=.*[A-Z]) :必须有大写字母
  • .{8,} :总长度至少8位
2. ​ 数据提取(捕获关键信息)​
  • 从URL提取域名和路径
^https?://([^/?#]+)([^?#]*)
  • 分组1 ([^/?#]+) 捕获域名(如 www.example.com
  • 分组2 ([^?#]*) 捕获路径(如 /path/to/page
  • 日志时间戳提取
\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}
  • 精确匹配 YYYY-MM-DD HH:MM:SS 格式
3. ​ 文本清洗与替换
  • 删除HTML标签
<[^>]+>
  • 匹配所有以 < 开头、 > 结尾的内容
  • 使用 re.sub(r'<[^>]+>', '', html) 替换为空
  • 格式化电话号码 输入: 1234567890 → 输出: (123) 456-7890
re.sub(r'(\d{3})(\d{3})(\d{4})', r'(\1) \2-\3', phone)

四、性能优化与避坑指南

1. ​ 避免灾难性回溯
  • 危险模式(a+)+.*.* (嵌套量词导致指数级复杂度)
  • 优化方法
  • 用具体字符代替 .* (如 \d+ 代替 .*
  • 使用原子分组 (?>...) (部分引擎支持)
  • 添加锚点限制范围(如 ^...$
2. ​ 贪婪与非贪婪选择
  • 贪婪模式 ​(默认): .* 匹配尽可能多内容

.*

→ 可能跨多个标签错误匹配
  • 非贪婪模式.*? 匹配最短结果

.*?

→ 精确匹配单个标签内容
3. ​ 预编译与复用
# 预编译提升性能(适用于频繁调用场景)
pattern = re.compile(r'\d{3}-\d{4}')
pattern.findall('Tel: 123-4567')

五、进阶技巧

1. ​ 零宽断言(Lookaround)​
  • (?=...) :正向先行断言(右侧必须满足条件)
\d+(?=px) → 匹配 "100px" 中的 "100"
  • (?<=...) :正向后行断言(左侧必须满足条件)
(?<=\$)\d+ → 匹配 "$200" 中的 "200"
2. ​ 条件匹配
(?(id)yes|no) → 根据分组是否存在选择分支
  • 示例:匹配带区号的电话号码
($)? \d{3} (?(1)$|) → 匹配 "(123)" 或 "123"

六、好用的工具

  1. 调试工具
  • RegExr:实时高亮匹配结果,显示分组与回溯
  • Regex101:支持多语言引擎,提供错误解释
  1. 可视化工具 Regexper:图形化展示正则逻辑

七、总结

正则表达式的核心在于 ​ 模式定义 与 ​ 引擎匹配机制 的结合。掌握以下要点即可应对90%的场景:

  1. 精准定位 :用 ^$\b 约束边界
  2. 明确范围 :用字符集合 [...] 和量词 {n,m} 减少模糊匹配
  3. 合理分组 :通过 ( ) 提取关键数据
  4. 性能优先 :避免嵌套量词,优先使用具体字符

以下是Python中正则表达式的用法


一、环境准备

  1. 导入re模块
import re # Python内置正则库
  1. 原始字符串(Raw String)

正则表达式推荐使用原始字符串(前缀 r ),避免Python字符串转义冲突:

pattern = r'\d+' # 正确:匹配数字
pattern = '\\d+' # 错误:需双重转义,可读性差

二、四大核心方法

  1. re.match() - ​ 从开头匹配
  • 只匹配字符串 开头 ,成功返回 Match对象 ,否则返回 None
text = "123abc"
result = re.match(r'\d+', text)
if result:
print("匹配成功:", result.group()) # 输出: 123
  1. re.search() - ​ 全局搜索
  • 扫描整个字符串,找到 第一个 匹配项
text = "abc456def"
result = re.search(r'\d+', text)
print(result.group()) # 输出: 456
  1. re.findall() - ​ 查找所有匹配
  • 返回所有匹配结果的 列表 ​(无分组时返回字符串列表)
text = "1a2b3c"
numbers = re.findall(r'\d', text)
print(numbers) # 输出: ['1', '2', '3']
  1. re.sub() - ​ 替换匹配内容
  • 将匹配内容替换为指定字符串
text = "2023-01-01"
new_text = re.sub(r'-', '/', text)
print(new_text) # 输出: 2023/01/01

三、分组与捕获

  1. 基本分组 ( )
  • 用括号分组,通过 group(index) 提取
text = "John:30"
pattern = r'(\w+):(\d+)'
match = re.search(pattern, text)
print(match.group(1)) # John
print(match.group(2)) # 30
  1. 非捕获分组 (?: )
  • 分组但不捕获,节省内存
text = "apple orange"
pattern = r'(?:a|an|the) (\w+)' # 匹配冠词后的单词但不捕获冠词
match = re.search(pattern, text)
print(match.group(1)) # apple
  1. 命名分组 (?P)
  • 为分组命名,提升可读性
text = "Date: 2023-08-15"
pattern = r'Date: (?P\d{4})-(?P\d{2})-(?P\d{2})'
match = re.search(pattern, text)
print(match.group('year')) # 2023
print(match.groupdict()) # {'year': '2023', 'month': '08', 'day': '15'}

四、高级功能

  1. 正则标志(Flags)
  • 控制匹配模式的全局行为
text = "Hello\nWorld"
# 多行模式(^和$匹配每行开头结尾)
re.findall(r'^\w+', text, flags=re.MULTILINE) # 输出: ['Hello', 'World']
# 忽略大小写
re.findall(r'hello', text, flags=re.IGNORECASE) # 输出: ['Hello']
  1. 预编译正则表达式
  • 提升重复使用时的性能
pattern = re.compile(r'\d{3}-\d{4}') # 编译为RegexObject
result = pattern.findall("Tel: 123-4567") # ['123-4567']
  1. 替换时使用函数
  • 动态生成替换内容
def to_upper(match):
return match.group().upper()

text = "hello world"
new_text = re.sub(r'\b\w', to_upper, text)
print(new_text) # 输出: Hello World

五、经典实战案例

  1. 验证邮箱格式
def validate_email(email):
pattern = r'^[\w-]+@[\w-]+\w+$'
return re.match(pattern, email) is not None

print(validate_email("user@example.com")) # True
print(validate_email("invalid.email@")) # False
  1. 提取HTML链接
html = '[Link](https://example.com)'
pattern = r'href="(https?://[^"]+)"'
match = re.search(pattern, html)
print(match.group(1)) # https://example.com
  1. 转换日期格式
date = "2023-08-15"
new_date = re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'\2/\3/\1', date)
print(new_date) # 08/15/2023

六、避坑指南

  1. 贪婪匹配陷阱

使用 .*? 非贪婪模式避免过度匹配:

text = "

Hello

World

"

re.findall(r'

(.*?)

‘, text) # [‘Hello’, ‘World’]

2. ​
**特殊字符转义**

匹配
`.`
、
`*`
等符号需转义:

```python
re.findall(r'314', "pi=3.14") # ['3.14']
  1. 性能优化

避免在循环中重复编译正则,优先使用预编译。


七、调试工具

  1. 在线测试

RegExr:实时高亮匹配结果,显示分组信息 2. ​ 代码调试

使用 re.DEBUG 标志查看正则解析过程:

re.compile(r'\d+', re.DEBUG)