Python 正则表达式(千字长文)

更新时间:

💡一则或许对你有用的小广告

欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论

截止目前, 星球 内专栏累计输出 90w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 3100+ 小伙伴加入学习 ,欢迎点击围观

前言

在 Python 开发中,正则表达式(Regular Expression)如同一把万能钥匙,能够解决文本处理中的复杂问题。无论是数据清洗、信息提取,还是自动化脚本开发,掌握 Python 正则表达式 都是提升效率的关键技能。本文将从零开始,通过通俗易懂的比喻、代码示例和实战案例,帮助编程初学者和中级开发者系统性地理解这一工具,并逐步掌握其核心逻辑与应用场景。


一、正则表达式基础概念与核心原理

1.1 什么是正则表达式?

正则表达式(Regex)是一种描述文本模式的符号语言,它通过特定的语法定义“规则”,从而匹配、查找或替换文本中的内容。可以将其想象为一个“文本密码锁”:开发者编写规则(密码),正则引擎根据规则在文本中寻找匹配的“钥匙”。

例如,规则 ^\d{3}-\d{4}$ 可以匹配格式为 123-4567 的字符串,其中:

  • ^ 表示字符串开头,$ 表示结尾
  • \d 表示数字,{3} 表示重复 3 次
  • - 是字面字符,需用反斜杠转义

1.2 Python 中的正则表达式模块

Python 内置的 re 模块提供了正则表达式功能。其核心流程分为两步:

  1. 编译模式:使用 re.compile() 将规则字符串转化为正则对象
  2. 执行匹配:通过正则对象的 search()findall() 等方法操作文本
import re  

pattern = re.compile(r'\d{3}-\d{4}')  

match = pattern.search("我的工号是 555-7890")  
print(match.group())  # 输出:555-7890  

1.3 正则表达式的核心元素

正则表达式由 普通字符元字符 组成:

  • 普通字符:直接匹配自身(如 a 匹配字符 "a")
  • 元字符:具有特殊含义的符号,例如 . 匹配任意单个字符,* 表示重复零次或多次

表 1:常见元字符及含义

元字符含义示例模式匹配内容
.匹配除换行符外的任意单个字符c.t"cat", "cut"
^匹配字符串的开头^hello"hello world"
$匹配字符串的结尾world$"hello world"
*匹配前一个字符零次或多次"colou?r""color", "colour"
+匹配前一个字符一次或多次"go+gle""google", "gogle"

二、正则表达式进阶语法与实战案例

2.1 字符集与量词:精准控制匹配范围

2.1.1 字符集(Character Set)

字符集用方括号 [] 定义,匹配其中任意一个字符。例如:

  • [aeiou] 匹配任意元音字母
  • [0-9] 匹配数字(等价于 \d
  • [^0-9] 匹配非数字字符(^ 在方括号内表示“非”)

案例:提取字符串中的邮箱域名部分:

email = "联系邮箱:user@example.com"  
domain_pattern = re.compile(r'@([a-zA-Z0-9.-]+)\.')  
match = domain_pattern.search(email)  
print(match.group(1))  # 输出:example  

2.1.2 量词:控制匹配次数的“交通灯”

量词决定前一个字符或组的重复次数,常见符号包括:

  • ?:0 次或 1 次(可有可无)
  • *:0 次或多次
  • +:1 次或多次
  • {n,m}:至少 n 次,最多 m 次

比喻:量词如同交通灯,控制字符的“通过次数”。例如:

  • a? 表示“红灯(禁止)或绿灯(允许)一次 a”
  • a+ 表示“必须绿灯,且可以继续通过多次”
pattern = re.compile(r'\d{1,3}')  
print(pattern.findall("ID: 45, 1234"))  # 输出:['45', '123']  

2.2 分组与捕获:提取特定内容的“筛选器”

分组通过 () 实现,可以:

  1. 捕获内容:通过 group() 方法提取子字符串
  2. 命名组:使用 (?P<name>...) 为分组命名,提升可读性

案例:从日志中提取时间、IP 和错误代码:

log = "2023-08-15 14:22:35 192.168.1.100 ERROR 404"  
pattern = re.compile(r'(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})\s+'  
                    r'(?P<ip>\d+\.\d+\.\d+\.\d+)\s+'  
                    r'(?P<level>\w+)\s+'  
                    r'(?P<code>\d+)')  
match = pattern.search(log)  
print(match.groupdict())  

2.3 特殊字符与转义:处理“危险”符号的“盾牌”

某些字符在正则表达式中有特殊含义,需用反斜杠 \ 转义。例如:

  • 匹配字面字符 . 需写为 \.
  • 匹配反斜杠本身需写为 \\

案例:验证文件路径的合法性(仅含字母、数字和下划线):

def validate_path(path):  
    pattern = re.compile(r'^[a-zA-Z0-9_]+$')  
    return bool(pattern.match(path))  

print(validate_path("valid_name"))   # True  
print(validate_path("invalid/name")) # False  

三、正则表达式的高级用法与优化技巧

3.1 前瞻与后顾:条件判断的“望远镜”

3.1.1 正向前瞻(Positive Lookahead)

语法:(?=...),表示“当前位置后面必须匹配 ...”但不包含在结果中。

案例:匹配以 .txt 结尾但非 temp.txt 的文件名:

pattern = re.compile(r'\b\w+(?<!temp)\.txt\b')  
print(pattern.findall("report.txt temp.txt data.txt"))  # 输出:['report.txt', 'data.txt']  

3.1.2 负向后顾(Negative Lookbehind)

语法:(?<!...),表示“当前位置前面不能匹配 ...”。

案例:匹配不以 // 开头的 URL 路径:

pattern = re.compile(r'(?<!//)\bhttps?://\S+')  
print(pattern.findall("//example.com https://google.com"))  # 输出:['https://google.com']  

3.2 贪婪与非贪婪匹配:控制“饥饿程度”的开关

默认的量词(如 .*)是贪婪模式,会尽可能多匹配字符。添加 ? 可切换为非贪婪模式:

text = "<title>Python正则表达式教程</title>"  
print(re.search(r'<title>.+</title>', text).group())  

print(re.search(r'<title>.*?</title>', text).group())  

3.3 性能优化:避免“死循环陷阱”

某些模式可能导致正则引擎陷入无限回溯,例如:

re.search(r'(a+)+', 'aaaa')  # 需要尝试所有可能的分组方式  

解决方案

  • 使用非捕获组 (?:...) 减少内存占用
  • 优先使用精确匹配而非模糊模式

四、实战场景与工具推荐

4.1 案例 1:提取网页中的所有链接

import re  

html = """<a href="https://example.com">Example</a>  
<img src="/static/logo.png">  
<script src="https://cdn.js"></script>"""  

pattern = re.compile(r'href=["\'](?P<url>.*?)["\']|src=["\'](?P<src>.*?)["\']')  
matches = pattern.finditer(html)  

for match in matches:  
    if match.group('url'):  
        print("URL:", match.group('url'))  
    elif match.group('src'):  
        print("Resource:", match.group('src'))  

4.2 案例 2:密码强度验证

def check_password_strength(pwd):  
    strength = 0  
    # 至少 8 位,包含大写字母、小写字母、数字  
    pattern = re.compile(r'^(?=.*[A-Z])(?=.*[a-z])(?=.*\d).{8,}$')  
    if pattern.match(pwd):  
        strength += 1  
    # 增加特殊字符要求  
    if re.search(r'[!@#$%^&*]', pwd):  
        strength += 1  
    return strength  

print(check_password_strength("Pass123!"))  # 输出:2  

4.3 工具推荐

  1. 在线测试工具
    • Regex101 :支持实时调试与解释
    • Pythex :专为 Python 正则设计
  2. IDE 插件
    • VS Code 的 "Regex" 扩展:提供语法高亮与验证

结论

Python 正则表达式 是文本处理的“瑞士军刀”,其灵活性与强大功能使其成为开发者工具箱中的必备技能。通过本文的讲解,读者可以掌握从基础语法到高级技巧的完整知识链,并通过实战案例理解其应用场景。建议读者通过以下步骤深化学习:

  1. 使用在线工具练习正则表达式
  2. 针对具体业务需求编写匹配规则
  3. 阅读 re 模块官方文档(Python 官方文档 - re 模块

正则表达式的学习如同攀登阶梯,初期可能感到抽象,但随着实践积累,终将掌握这一高效工具的精髓。

最新发布