Python正则表达式re模块用法

正则表达式处理字符串的核心是re模块,主要用四个函数:match、search、findall、sub。记住一点:match从开头匹配,search扫描整个字符串找第一个,findall返回所有匹配,sub做替换。 基本匹配
import re

text = "我的手机号是13800138000,备用号13912345678"
pattern = r"1[3-9]\d{9}"  # 手机号规则:1开头,位3-9,后面9位数字

# search只返回第一个
result = re.search(pattern, text)
print(result.group())  # 13800138000

# findall返回所有
results = re.findall(pattern, text)
print(results)  # ['13800138000', '13912345678']
raw string前面的r必须加,不然反斜杠要写两遍。比如`\d`不写r就得写成`\\d`,坑过我好几次。 分组提取 用括号分组,group(0)是整个匹配,group(1)往后是各个分组。
text = "姓名:张三,年龄:25;姓名:李四,年龄:30"
pattern = r"姓名:(\w+),年龄:(\d+)"
matches = re.findall(pattern, text)
print(matches)  # [('张三', '25'), ('李四', '30')]

# 需要同时提取多个字段时用findall配合分组最方便
for name, age in matches:
    print(f"{name}今年{age}岁")
编译正则对象 如果同一个正则要多次使用,用compile预编译,性能提升明显。
# 编译一次,多次复用
phone_pattern = re.compile(r"1[3-9]\d{9}")
text1 = "联系我:13800138000"
text2 = "备用:13912345678"

print(phone_pattern.findall(text1))  # ['13800138000']
print(phone_pattern.findall(text2))  # ['13912345678']
常用模式修饰符 re.IGNORECASE忽略大小写,re.MULTILINE让^$匹配每行开头结尾。
text = "Python\npython\nPYTHON"
# 不加修饰符只匹配小写
print(re.findall(r"^python", text, re.MULTILINE))  # ['python']
print(re.findall(r"^python", text, re.MULTILINE | re.IGNORECASE))  
# ['Python', 'python', 'PYTHON']
替换与分割 sub可以做变量替换,subn额外返回替换次数。
text = "我的邮箱是test@example.com,备用邮箱是admin@test.com"
# 隐藏邮箱用户名
def mask_email(match):
    username, domain = match.group(1), match.group(2)
    return f"{username[0]}***@{domain}"

result = re.sub(r"(\w+)@(\w+\.\w+)", mask_email, text)
print(result)  # 我的邮箱是t***@example.com,备用邮箱是a***@test.com

# split分割,比str.split强大
log = "2024-01-01 12:00:00 ERROR 连接超时"
parts = re.split(r"[\s:]+", log)
print(parts)  # ['2024', '01', '01', '12', '00', '00', 'ERROR', '连接超时']
实战:日志解析 解析Nginx日志提取IP和状态码,这个需求我经常遇到。
log_line = '192.168.1.1 - - [10/Jan/2024:13:55:36 +0800] "GET /api/users HTTP/1.1" 200 2326'
pattern = r'(\d+\.\d+\.\d+\.\d+).*?"(\w+) .*?" (\d{3})'

match = re.search(pattern, log_line)
if match:
    ip, method, status = match.groups()
    print(f"IP:{ip}, 方法:{method}, 状态码:{status}")
    # 输出: IP:192.168.1.1, 方法:GET, 状态码:200
贪婪与非贪婪 默认是贪婪匹配,加?变成非贪婪。这个坑踩过好几次。
html = "<div>内容1</div><div>内容2</div>"
# 贪婪匹配:从第一个<到一个>
print(re.findall(r"<div>.*</div>", html))
# ['<div>内容1</div><div>内容2</div>']

# 非贪婪:匹配最短
print(re.findall(r"<div>.*?</div>", html))
# ['<div>内容1</div>', '<div>内容2</div>']
性能提示 写正则时避免灾难性回溯。比如`(a+)+b`这种嵌套量词,遇到不匹配的字符串会让CPU跑满。我遇到过线上服务因为这个导致响应超时,排查了很久才发现是正则问题。简单规则:少用嵌套量词,能用`[^]`就不用`.`。 实际场景:批量替换配置文件 之前帮雨云处理服务器配置,要把所有旧域名替换成新域名,用re.sub一行搞定。
config = """
server_name old.example.com;
proxy_pass http://old.example.com:8080;
"""
new_config = re.sub(r"old\.example\.com", "new.example.com", config)
print(new_config)
# server_name new.example.com;
# proxy_pass http://new.example.com:8080;
注意点号要转义,不然匹配任意字符。 记住几个常用模式 – `[\u4e00-\u9fa5]` 匹配中文 – `(?P…)` 命名分组,用group(‘name’)取值 – `(?!…)` 否定前瞻,匹配后面不是…的位置 – `(?<=…)` 肯定后顾,匹配前面是…的位置 后顾和前瞻在复杂过滤时很好用,比如提取价格但不包括美元符号:`(?<=\$)\d+`。 re模块就这些核心用法。遇到复杂场景先画正则逻辑图,再逐段测试,比一次性写完再debug快得多。

雨云是国内一家老牌云服务商,提供高性价比的云服务器和虚拟主机。我用它部署了好几个项目,速度和稳定性都不错。通过 https://www.rainyun.com/SAJA_ 注册可以领一张 5折优惠券,有需要的朋友可以看看。

© 版权声明
THE END
喜欢就支持一下吧
点赞11 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容