正则表达式的高效应用

你有没有遇到过这种场景?

  • 爬取的电商评论里混着几十种格式的手机号,手动筛选太慢?
  • 整理的办公文档里有全角半角逗号、分号甚至空格分隔的课程名单,str.split() 根本切不干净?
  • 处理聊天机器人历史记录时,要把所有敏感词一键替换成 * 且忽略大小写?

这时候,正则表达式(Regular Expression,简称 Regex) 这把“文本处理瑞士军刀”就能派上大用场——一套规则搞定所有复杂文本特征的描述、匹配与处理,也是 Daoman Python AI 在爬虫、日志分析、自动化办公脚本里的核心工具。


1. 正则核心语法:看懂30%就能覆盖80%场景

正则由普通字符(比如纯字母 a、数字 5)和赋予描述能力的元字符组成,新手不用死记硬背所有符号,先记住这张高频速查表就行:

符号解释示例匹配结果
.匹配除换行符外的任意单个字符b.tbatb1tb#t
\d匹配数字(等价于 [0-9]\d{3}123955
\w匹配字母、数字、下划线(等价于 [a-zA-Z0-9_]\w+python_3hello
\s匹配任意空白符(空格、\t\nlove\syoulove youlove you
^ / $严格匹配字符串的开头 / 结尾^The仅匹配开头是 The 的行
[]匹配字符集中的任一字符[aeiou]aeo
* / +重复0次或多次 / 至少1次\d+11234
?匹配0次或1次(或开启非贪婪模式)https?httphttps

💡 转义保命提示:如果要匹配正则里的特殊符号本身(比如域名里的 .、分组用的 (),一定要加反斜杠转义成 \.\(


2. Python 的 re 模块:6个核心函数就够了

Python 内置的 re 模块封装了所有正则功能,不用额外安装第三方库。同样,高频场景只需要记住这6个函数:

核心函数功能说明适合场景
re.compile(pattern)预编译正则模式,多次调用效率翻倍循环里重复用同一个正则(比如处理10万条日志)
re.match()从字符串第一个字符开始严格匹配验证开头格式(比如是否是邮箱前缀)
re.search()扫描整个字符串,找第一个匹配项找文本里的第一个关键词
re.findall()所有匹配项,返回字符串列表批量提取手机号、邮箱
re.sub()一键替换所有匹配项敏感词过滤、格式统一
re.split()根据正则模式灵活拆分处理多分隔符混合的文本

3. 高频实战案例:拿来就能改

直接说语法太干,看几个Python办公/爬虫/日常高频能用的案例:

案例1:一键敏感词过滤(忽略大小写)

re.sub + re.IGNORECASE(缩写 re.I) 就能搞定,支持“或”匹配和模糊字符集:

import re

# 模拟一堆带敏感词的文本
raw_comment = "Oh, Shit! 你是傻逼吗? Fuck you. 沙比东西"
# 模糊匹配模式:用 | 连精确关键词,[] 连谐音/形近字
sensitive_pattern = r'fuck|shit|[傻煞沙][比笔逼叉缺雕]'
# 替换为 *,加 re.I 忽略大小写
clean_comment = re.sub(sensitive_pattern, '*', raw_comment, flags=re.I)
print(clean_comment)  # 输出:Oh, *! 你是*吗? * you. *东西

案例2:批量提取合规手机号

re.findall 从杂乱文本里捞数据,这里用简化版的国内手机号规则(1开头,第二位3-9,后面9位数字):

import re

# 模拟日志里的杂乱文本
raw_log = "下单人:张三,电话13512345678;投诉人:李四,留的不是110,是15688889999"
# 注意:加 ^/$ 是严格验证整个字符串,但这里是从日志里捞,不用加
phone_pattern = r'1[3-9]\d{9}'
phones = re.findall(phone_pattern, raw_log)
print(phones)  # 输出:['13512345678', '15688889999']

案例3:多分隔符混合文本拆分

当文本有全角半角、空格、竖线等一堆分隔符时,str.split() 只能处理单一分隔符,正则 re.split() 能通吃:

import re

# 模拟课程名单(逗号、分号、竖线、1个以上空格混合)
raw_course = "Python,Java;Go  C++|Rust,TypeScript"
# 分隔符模式:匹配逗号、分号、竖线、中文逗号,或1个以上的空白
split_pattern = r'[,;;\|\s,]+'
courses = re.split(split_pattern, raw_course)
print(courses)  # 输出:['Python', 'Java', 'Go', 'C++', 'Rust', 'TypeScript']

4. 新手必踩的坑:贪婪 vs 非贪婪匹配

这是最容易出错的地方,一句话总结:

  • 贪婪模式(默认):尽可能「多吃」匹配内容
  • 非贪婪模式(加 ?:尽可能「少吃」,遇到第一个符合条件的结束标记就停

看个HTML标签提取的对比就懂了:

import re

html_text = "<div>苹果</div><div>香蕉</div>"

# 贪婪模式:从第一个 <div> 吃到最后一个 </div>
greedy_result = re.findall(r'<div>.*</div>', html_text)
print(greedy_result)  # 输出:['<div>苹果</div><div>香蕉</div>']

# 非贪婪模式:在 .* 后面加 ?,遇到第一个 </div> 就停
lazy_result = re.findall(r'<div>.*?</div>', html_text)
print(lazy_result)  # 输出:['<div>苹果</div>', '<div>香蕉</div>']

最后:3个避坑/提效小技巧

  1. 必须用原始字符串 r'':Python 字符串本身有转义(比如 \n 是换行),加 r 可以避免和正则的转义冲突
  2. 循环前务必预编译:如果一个正则要在循环里用1000次以上,先用 compiled = re.compile(pattern) 存起来,再用 compiled.findall(),效率能提30%-50%
  3. 先在线调试再写代码:推荐用 regex101.com,它能可视化匹配过程,还能自动生成Python/Java/JS等语言的代码

(全文完,约2000字)