← 返回首页
🧩

正则表达式进阶

📂 python ⏱ 2 min 242 words

正则表达式进阶

本文将深入探讨正则表达式的高级特性,包括编译优化、复杂替换操作以及贪婪与非贪婪模式的使用。

编译正则表达式

当同一个模式需要多次使用时,先编译可以提高性能:

import re

# 编译正则表达式
email_pattern = re.compile(r'[\w.+-]+@[\w-]+\.[\w.]+')

# 多次使用
text1 = "联系我: test@example.com"
text2 = "邮箱: user@domain.org"

print(email_pattern.search(text1).group())  # test@example.com
print(email_pattern.findall(text2))         # ['user@domain.org']

查找与替换

import re

# sub - 替换所有匹配
text = "2024年1月15日,气温-5摄氏度"
result = re.sub(r'\d+', '#', text)
print(result)  # 2024年#月#日,气温-#摄氏度

# subn - 替换并返回替换次数
result, count = re.subn(r'\d+', '#', text)
print(f"替换{count}次: {result}")

# 替换函数
def double_number(match):
    return str(int(match.group()) * 2)

result = re.sub(r'\d+', double_number, "价格: 100元,数量: 5个")
print(result)  # 价格: 200元,数量: 10个

# 使用lambda
result = re.sub(r'(\w+)@(\w+)', lambda m: f'{m.group(2)}@{m.group(1)}', 
                'a@b.com')
print(result)  # b@a.com

贪婪与非贪婪

默认情况下,正则表达式是贪婪的,尽可能多地匹配:

import re

text = '<div>内容1</div><div>内容2</div>'

# 贪婪模式(默认)
greedy = re.findall(r'<div>.*</div>', text)
print(greedy)  # ['<div>内容1</div><div>内容2</div>']

# 非贪婪模式 - 在量词后加 ?
non_greedy = re.findall(r'<div>.*?</div>', text)
print(non_greedy)  # ['<div>内容1</div>', '<div>内容2</div>']

# 更多示例
text = 'aaa'
print(re.findall(r'a+', text))      # ['aaa'](贪婪)
print(re.findall(r'a+?', text))     # ['a', 'a', 'a'](非贪婪)

前向/后向断言

import re

# 正向前瞻 - 后面必须跟...
text = "价格: 100元"
result = re.findall(r'\d+(?=元)', text)
print(result)  # ['100']

# 负向前瞻 - 后面不能跟...
text = "100元 200美元"
result = re.findall(r'\d+(?!元)', text)
print(result)  # ['1', '2', '2', '0', '0']

# 正向后顾 - 前面必须是...
text = "温度: -5度"
result = re.findall(r'(?<=: )-?\d+', text)
print(result)  # ['-5']

# 负向后顾 - 前面不能是...
text = "test123 test456"
result = re.findall(r'(?<!\d)\d+', text)

分组替换

import re

# 交换姓名
name = "John Smith"
swapped = re.sub(r'(\w+) (\w+)', r'\2 \1', name)
print(swapped)  # Smith John

# HTML标签提取
html = '<a href="https://example.com">链接</a>'
match = re.search(r'<a href="(.*?)">(.*?)</a>', html)
if match:
    print(f"链接: {match.group(1)}, 文本: {match.group(2)}")

实战:日志解析

import re
from datetime import datetime

log_pattern = re.compile(
    r'(?P<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})'
    r' \[(?P<level>\w+)\]'
    r' (?P<message>.*)'
)

log = "2024-01-15 10:30:45 [ERROR] 连接失败"
match = log_pattern.search(log)
if match:
    data = match.groupdict()
    print(f"时间: {data['time']}")
    print(f"级别: {data['level']}")
    print(f"消息: {data['message']}")

掌握这些进阶技巧,能让你更高效地处理复杂的文本匹配和替换任务。