Python正则表达式re模块全解析

Python正则表达式全面指南:re标准库详解与实践

正则表达式是处理字符串的强大工具,Python通过内置的re模块提供了完整的正则表达式功能。本文将全面介绍正则表达式的基础语法、re模块的核心函数以及实际应用场景。

一、正则表达式基础语法

1.1 基本元字符

正则表达式由普通字符和元字符组成,元字符具有特殊含义:

元字符 功能说明 示例
. 匹配任意单个字符(除换行符) a.c 匹配 "abc"、"a c"
^ 匹配字符串开头 ^Hello 匹配以"Hello"开头的字符串
$ 匹配字符串结尾 world$ 匹配以"world"结尾的字符串
* 匹配前一个字符0次或多次 ab*c 匹配 "ac"、"abc"、"abbc"
+ 匹配前一个字符1次或多次 ab+c 匹配 "abc"、"abbc"
? 匹配前一个字符0次或1次 ab?c 匹配 "ac"、"abc"
{m,n} 匹配前一个字符m到n次 a{2,4} 匹配 "aa"、"aaa"、"aaaa"

1.2 字符集与预定义字符类

python 复制代码
import re

# 字符集示例
text = "cat bat hat rat"
pattern1 = r'[bc]at'  # 匹配"bat"或"cat"
matches1 = re.findall(pattern1, text)
print(f"字符集匹配: {matches1}")  # 输出: ['cat', 'bat']

# 预定义字符类
text2 = "价格: $100, 重量: 5kg, 日期: 2024-01-01"
pattern2 = r'\d+'  # 匹配一个或多个数字
matches2 = re.findall(pattern2, text2)
print(f"数字匹配: {matches2}")  # 输出: ['100', '5', '2024', '01', '01']

常用预定义字符类:

字符类 等价表示 说明
\d [0-9] 数字字符
\D [^0-9] 非数字字符
\w [a-zA-Z0-9_] 单词字符
\W [^a-zA-Z0-9_] 非单词字符
\s `[ \t
\r\f\v]` 空白字符
\S `[^ \t
\r\f\v]` 非空白字符

二、re模块核心函数详解

2.1 匹配函数对比

函数 功能 返回值 适用场景
re.match() 从字符串起始位置匹配 Match对象或None 验证字符串格式
re.search() 扫描整个字符串查找匹配 Match对象或None 查找第一个匹配项
re.findall() 查找所有匹配项 列表 提取所有符合条件的内容
re.finditer() 查找所有匹配项 迭代器 处理大量匹配时节省内存
re.sub() 替换匹配项 替换后的字符串 字符串清洗和格式化
re.split() 根据模式分割字符串 列表 复杂字符串分割

2.2 re.match() - 起始位置匹配

re.match()从字符串的起始位置开始匹配,如果起始位置不符合模式,则返回None。

python 复制代码
import re

# re.match() 示例
def test_match():
    patterns = [
        r'hello',
        r'\d+',
        r'^Python'
    ]
    
    test_strings = [
        "hello world",
        "123abc",
        "Python is great",
        "Hi Python"
    ]
    
    for test_str in test_strings:
        print(f"
测试字符串: '{test_str}'")
        for pattern in patterns:
            match = re.match(pattern, test_str)
            if match:
                print(f"  模式 '{pattern}' 匹配成功: {match.group()}")
            else:
                print(f"  模式 '{pattern}' 匹配失败")

test_match()

2.3 re.search() - 全局搜索匹配

re.search()扫描整个字符串,返回第一个匹配的对象。

python 复制代码
import re

# re.search() 示例
def test_search():
    text = "我的电话是138-1234-5678,另一个电话是139-8765-4321"
    
    # 搜索电话号码
    phone_pattern = r'\d{3}-\d{4}-\d{4}'
    match = re.search(phone_pattern, text)
    
    if match:
        print(f"找到电话号码: {match.group()}")  # 输出: 找到电话号码: 138-1234-5678
        print(f"匹配位置: {match.start()} - {match.end()}")  # 输出: 匹配位置: 5 - 18
        print(f"匹配范围: {match.span()}")  # 输出: 匹配范围: (5, 18)
    else:
        print("未找到电话号码")

test_search()

2.4 re.findall() - 查找所有匹配

re.findall()返回字符串中所有非重叠匹配的列表。

python 复制代码
import re

# re.findall() 示例
def test_findall():
    # 示例1: 提取所有电子邮件
    text1 = "联系我们: admin@example.com, sales@company.org, support@test.cn"
    email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
    emails = re.findall(email_pattern, text1)
    print(f"找到的邮箱: {emails}")
    
    # 示例2: 提取HTML标签中的内容
    html_text = "<h1>标题</h1><p>段落内容</p><div>容器</div>"
    tag_content = re.findall(r'<[^>]+>([^<]+)</[^>]+>', html_text)
    print(f"标签内容: {tag_content}")
    
    # 示例3: 提取价格信息
    price_text = "商品A: ¥100.50, 商品B: $200.75, 商品C: €150.00"
    prices = re.findall(r'[¥$€](\d+\.\d+)', price_text)
    print(f"价格: {prices}")

test_findall()

2.5 re.finditer() - 返回匹配迭代器

re.finditer()返回一个迭代器,逐个产生Match对象,适合处理大量数据。

python 复制代码
import re

# re.finditer() 示例
def test_finditer():
    text = """
    用户信息:
    姓名: 张三, 年龄: 25, 城市: 北京
    姓名: 李四, 年龄: 30, 城市: 上海
    姓名: 王五, 年龄: 28, 城市: 广州
    """
    
    # 使用命名分组提取信息
    pattern = r'姓名:\s*(?P<name>\w+),\s*年龄:\s*(?P<age>\d+),\s*城市:\s*(?P<city>\w+)'
    
    print("用户信息提取:")
    for match in re.finditer(pattern, text):
        name = match.group('name')
        age = match.group('age')
        city = match.group('city')
        print(f"  {name}, {age}岁, 来自{city}")

test_finditer()

2.6 re.sub() - 替换匹配内容

re.sub()用于替换字符串中的匹配项。

python 复制代码
import re

# re.sub() 示例
def test_sub():
    # 示例1: 敏感信息脱敏
    text1 = "银行卡号: 6225-3801-2345-6789, 身份证: 110101199001011234"
    
    # 银行卡号脱敏
    desensitized_bank = re.sub(r'\d{4}-\d{4}-\d{4}-', '****-****-****-', text1)
    # 身份证号脱敏
    desensitized_id = re.sub(r'(\d{6})\d{8}(\d{4})', r'\1********\2', desensitized_bank)
    
    print(f"脱敏后: {desensitized_id}")
    
    # 示例2: 日期格式转换
    date_text = "今天是2024/01/15,会议在2024-02-20"
    standardized_date = re.sub(r'(\d{4})[/-](\d{2})[/-](\d{2})', r'\1年\2月\3日', date_text)
    print(f"日期标准化: {standardized_date}")
    
    # 示例3: 使用函数进行复杂替换
    def multiply_numbers(match):
        number = int(match.group())
        return str(number * 2)
    
    math_text = "数字: 10, 20, 30"
    doubled_text = re.sub(r'\d+', multiply_numbers, math_text)
    print(f"数字加倍: {doubled_text}")

test_sub()

2.7 re.split() - 模式分割字符串

re.split()使用正则表达式模式分割字符串。

python 复制代码
import re

# re.split() 示例
def test_split():
    # 示例1: 复杂分隔符分割
    text1 = "苹果,香蕉;橙子|葡萄 西瓜"
    fruits = re.split(r'[,;|\s]+', text1)
    print(f"水果列表: {fruits}")
    
    # 示例2: 保留分隔符
    text2 = "100+200-300*400/500"
    # 使用捕获分组保留运算符
    parts = re.split(r'([+*-/])', text2)
    print(f"分割结果: {parts}")
    
    # 示例3: 多空格分割
    text3 = "这    是    一个    有很多    空格的    文本"
    words = re.split(r'\s+', text3)
    print(f"单词列表: {words}")

test_split()

三、高级功能与实战应用

3.1 分组与捕获

分组是正则表达式的重要特性,可以提取子匹配内容。

python 复制代码
import re

# 分组捕获示例
def group_demo():
    # 提取日志信息
    log_entry = "2024-01-15 14:30:25 [INFO] User login successful (user_id: 12345)"
    
    # 使用命名分组
    log_pattern = r'(?P<date>\d{4}-\d{2}-\d{2})\s+(?P<time>\d{2}:\d{2}:\d{2})\s+\[(?P<level>\w+)\]\s+(?P<message>.*?)\s+\(user_id:\s*(?P<user_id>\d+)\)'
    
    match = re.search(log_pattern, log_entry)
    if match:
        print("日志解析结果:")
        print(f"  日期: {match.group('date')}")
        print(f"  时间: {match.group('time')}")
        print(f"  级别: {match.group('level')}")
        print(f"  消息: {match.group('message')}")
        print(f"  用户ID: {match.group('user_id')}")
    
    # 非捕获分组
    text = "color colour"
    # 使用非捕获分组 (?:)
    pattern = r'col(?:ou)?r'
    matches = re.findall(pattern, text)
    print(f"颜色匹配: {matches}")

group_demo()

3.2 贪婪匹配与非贪婪匹配

正则表达式默认使用贪婪匹配,可以通过?改为非贪婪匹配。

python 复制代码
import re

# 贪婪vs非贪婪匹配
def greedy_vs_lazy():
    html_text = "<div>内容1</div><div>内容2</div><div>内容3</div>"
    
    # 贪婪匹配 - 匹配最长的可能
    greedy_pattern = r'<div>.*</div>'
    greedy_match = re.search(greedy_pattern, html_text)
    print(f"贪婪匹配: {greedy_match.group() if greedy_match else '无匹配'}")
    
    # 非贪婪匹配 - 匹配最短的可能
    lazy_pattern = r'<div>.*?</div>'
    lazy_matches = re.findall(lazy_pattern, html_text)
    print(f"非贪婪匹配: {lazy_matches}")

greedy_vs_lazy()

3.3 标志参数的使用

re模块支持多种标志参数来改变匹配行为。

python 复制代码
import re

# 标志参数示例
def flags_demo():
    text = "Hello
World
Python"
    
    # 多行模式 - 让^和$匹配每行的开头和结尾
    multiline_matches = re.findall(r'^\w+', text, re.MULTILINE)
    print(f"多行模式匹配: {multiline_matches}")
    
    # 忽略大小写
    case_insensitive = re.findall(r'hello', text, re.IGNORECASE)
    print(f"忽略大小写匹配: {case_insensitive}")
    
    # 点号匹配所有字符(包括换行符)
    dotall_match = re.search(r'Hello.*Python', text, re.DOTALL)
    print(f"点号匹配所有: {dotall_match.group() if dotall_match else '无匹配'}")

flags_demo()

3.4 编译正则表达式

对于需要重复使用的模式,可以先编译再使用,提高效率。

python 复制代码
import re
import time

# 编译正则表达式示例
def compile_demo():
    # 准备测试数据
    emails = [f"user{i}@example.com" for i in range(1000)]
    
    # 未编译的方式
    start_time = time.time()
    pattern = r'^[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}$'
    valid_emails = []
    for email in emails:
        if re.match(pattern, email):
            valid_emails.append(email)
    uncompiled_time = time.time() - start_time
    
    # 编译后的方式
    start_time = time.time()
    compiled_pattern = re.compile(pattern)
    valid_emails_compiled = []
    for email in emails:
        if compiled_pattern.match(email):
            valid_emails_compiled.append(email)
    compiled_time = time.time() - start_time
    
    print(f"未编译方式耗时: {uncompiled_time:.4f}秒")
    print(f"编译后方式耗时: {compiled_time:.4f}秒")
    print(f"性能提升: {(uncompiled_time - compiled_time)/uncompiled_time*100:.1f}%")

compile_demo()

四、实战应用案例

4.1 数据验证

python 复制代码
import re

# 数据验证函数
def data_validation():
    def validate_email(email):
        pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
        return bool(re.match(pattern, email))
    
    def validate_phone(phone):
        pattern = r'^1[3-9]\d{9}$'  # 中国手机号
        return bool(re.match(pattern, phone))
    
    def validate_id_card(id_card):
        pattern = r'^\d{17}[\dXx]$'  # 简化版身份证验证
        return bool(re.match(pattern, id_card))
    
    # 测试验证
    test_data = [
        "test@example.com",
        "13812345678", 
        "110101199001011234",
        "invalid-email",
        "12345678901",
        "ABC12345678901234"
    ]
    
    print("数据验证结果:")
    for data in test_data:
        email_valid = validate_email(data)
        phone_valid = validate_phone(data)
        id_valid = validate_id_card(data)
        
        print(f"  '{data}': 邮箱({email_valid}), 手机({phone_valid}), 身份证({id_valid})")

data_validation()

4.2 文本数据提取

python 复制代码
import re

# 文本数据提取
def text_extraction():
    # 复杂的文本数据
    complex_text = """
    订单信息:
    订单号: ORD20240115001, 金额: ¥1,250.50, 状态: 已完成
    客户: 张三, 电话: 138-1234-5678, 邮箱: zhangsan@email.com
    地址: 北京市朝阳区xxx街道100号
    
    商品清单:
    1. 笔记本电脑 - 数量: 1 - 单价: ¥8,999.00
    2. 鼠标 - 数量: 2 - 单价: ¥150.00
    3. 键盘 - 数量: 1 - 单价: ¥450.00
    """
    
    # 提取订单基本信息
    order_info = {}
    
    # 提取订单号
    order_match = re.search(r'订单号:\s*(\w+)', complex_text)
    if order_match:
        order_info['order_no'] = order_match.group(1)
    
    # 提取金额(处理千分位分隔符)
    amount_match = re.search(r'金额:\s*¥([\d,]+\.\d+)', complex_text)
    if amount_match:
        amount = amount_match.group(1).replace(',', '')
        order_info['amount'] = float(amount)
    
    # 提取客户信息
    customer_match = re.search(r'客户:\s*(\w+)', complex_text)
    if customer_match:
        order_info['customer'] = customer_match.group(1)
    
    # 提取商品信息
    products = []
    product_pattern = r'(\d+)\.\s*([^-]+)\s*-\s*数量:\s*(\d+)\s*-\s*单价:\s*¥([\d,]+\.\d+)'
    
    for match in re.finditer(product_pattern, complex_text):
        product = {
            'seq': match.group(1),
            'name': match.group(2).strip(),
            'quantity': int(match.group(3)),
            'price': float(match.group(4).replace(',', ''))
        }
        products.append(product)
    
    order_info['products'] = products
    
    print("提取的订单信息:")
    for key, value in order_info.items():
        if key != 'products':
            print(f"  {key}: {value}")
        else:
            print("  商品清单:")
            for product in value:
                print(f"    {product['seq']}. {product['name']} - {product['quantity']}件 - ¥{product['price']}")

text_extraction()

4.3 日志分析

python 复制代码
import re
from collections import Counter

# 日志分析
def log_analysis():
    # 模拟日志数据
    logs = """
    2024-01-15 08:30:15 [INFO] User login successful: user123
    2024-01-15 08:35:22 [ERROR] Database connection failed
    2024-01-15 08:40:10 [WARN] High memory usage detected
    2024-01-15 09:15:30 [INFO] File upload completed: file.pdf
    2024-01-15 09:20:45 [ERROR] Permission denied for user: user456
    2024-01-15 10:05:18 [INFO] User logout: user123
    2024-01-15 10:30:55 [ERROR] Invalid API request
    """
    
    # 分析日志级别分布
    level_pattern = r'\[(\w+)\]'
    levels = re.findall(level_pattern, logs)
    level_count = Counter(levels)
    
    print("日志级别统计:")
    for level, count in level_count.items():
        print(f"  {level}: {count}次")
    
    # 提取错误日志的详细信息
    error_pattern = r'\[ERROR\]\s*(.+)'
    errors = re.findall(error_pattern, logs)
    
    print("
错误日志详情:")
    for i, error in enumerate(errors, 1):
        print(f"  {i}. {error}")
    
    # 提取用户操作
    user_actions = re.findall(r'User\s+(\w+):\s*(\w+)', logs)
    print("
用户操作记录:")
    for action, user in user_actions:
        print(f"  用户 {user} 执行了 {action} 操作")

log_analysis()

五、性能优化与最佳实践

5.1 性能优化技巧

python 复制代码
import re
import time

def performance_tips():
    # 1. 使用原始字符串
    good_pattern = r'\d+\.\d+'  # 推荐
    bad_pattern = '\\d+\\.\\d+'  # 不推荐
    
    # 2. 避免回溯灾难
    text = "aaaaaaaaaaaaaaaaaaaaab"
    
    # 糟糕的模式 -  catastrophic backtracking
    start_time = time.time()
    try:
        bad_match = re.search(r'(a+)+b', text)
        bad_time = time.time() - start_time
    except:
        bad_time = float('inf')
    
    # 优化的模式
    start_time = time.time()
    good_match = re.search(r'a+b', text)
    good_time = time.time() - start_time
    
    print(f"糟糕模式耗时: {bad_time:.6f}秒")
    print(f"优化模式耗时: {good_time:.6f}秒")
    
    # 3. 使用适当的量词
    text2 = "<div>content</div>" * 1000
    
    # 贪婪量词
    start_time = time.time()
    greedy_result = re.findall(r'<div>.*</div>', text2)
    greedy_time = time.time() - start_time
    
    # 非贪婪量词
    start_time = time.time()
    lazy_result = re.findall(r'<div>.*?</div>', text2)
    lazy_time = time.time() - start_time
    
    print(f"贪婪量词匹配{len(greedy_result)}次,耗时: {greedy_time:.6f}秒")
    print(f"非贪婪量词匹配{len(lazy_result)}次,耗时: {lazy_time:.6f}秒")

performance_tips()

5.2 错误处理与调试

python 复制代码
import re

def error_handling():
    def safe_re_search(pattern, text, flags=0):
        try:
            compiled = re.compile(pattern, flags)
            return compiled.search(text)
        except re.error as e:
            print(f"正则表达式错误: {e}")
            return None
    
    # 测试错误处理
    test_cases = [
        (r'valid_pattern\d+', 'text123'),
        (r'invalid[pattern', 'text'),  # 未闭合字符集
        (r'*invalid', 'text'),         # 量词使用错误
    ]
    
    for pattern, text in test_cases:
        print(f"
测试模式: {pattern}")
        result = safe_re_search(pattern, text)
        if result:
            print(f"  匹配成功: {result.group()}")
        else:
            print("  匹配失败或模式错误")

error_handling()

正则表达式是Python文本处理的利器,通过熟练掌握re模块的各种函数和正则表达式语法,可以高效解决复杂的字符串处理问题。在实际应用中,建议根据具体需求选择合适的函数,注意性能优化,并妥善处理可能的异常情况。


参考来源

相关推荐
李昊哲小课2 小时前
Python 文件路径操作详细教程
linux·服务器·python
Cyber4K2 小时前
【妙招系列】在Linux中测试自己邮箱是否可接收邮件?
linux·运维·python
Ama_tor2 小时前
FLASK|完整版学习(ALL)
python·学习·flask
郝学胜-神的一滴2 小时前
深度学习:CNN 与 RNN——解锁多模态处理能力
人工智能·python·rnn·深度学习·神经网络·cnn
七月初七773 小时前
使用Python连接MySQL数据库
数据库·python·mysql
测试19983 小时前
自动化测试:selenium详解
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
进击的小头3 小时前
第5篇:最优控制问题的组成
python·算法
hhzz3 小时前
JupyterLab、Jupyter Notebook 和 Voilà 的安装与使用指南
ide·python·jupyter
这辈子谁会真的心疼你3 小时前
修改视频拍摄时间会被发现吗?修改视频拍摄时间的方法
python·音视频