re.match()仅从字符串开头匹配,等价于正则前加^;re.search()才全局查找;验证整串格式应使用re.fullmatch();高频匹配需预编译re.compile();贪婪匹配应优先用.*?或否定字符集。

re.match() 和 re.search() 混用导致匹配失败
很多人默认 re.match() 就是“找字符串里有没有这个模式”,结果发现明明存在却返回 None。它只从字符串开头匹配,哪怕后面有完全符合的子串也无视。re.search() 才是真正“全局查找”。
- 用
re.match()时,等价于在正则前加了^锚定,比如re.match(r'abc', 'xabc')一定失败 - 想验证整个字符串是否符合某格式(如邮箱、日期),用
re.fullmatch()更准确,避免漏掉结尾校验 - 性能上,
match()在确定从头开始时略快,但误用带来的逻辑 bug 远比这点开销代价大
忘记 re.compile() 缓存,高频调用拖慢程序
在循环里反复写 re.search(r'\d+', text),Python 每次都重新编译正则,开销明显。尤其当正则复杂或文本量大时,CPU 时间可能多花 2–5 倍。
- 把正则提成模块级变量:
PHONE_PATTERN = re.compile(r'1[3-9]\d{9}'),后续直接调用PHONE_PATTERN.search(text) -
re.compile()返回的对象支持findall()、sub()、split()等全部方法,接口一致 - 如果正则带标志(如
re.I),必须在compile()时传入,不能在search()里再加——后者会被忽略
贪婪匹配没控制好,吃掉不该吃的字符
.* 看似方便,实际常导致跨段落、跨标签甚至整行吞掉。比如 re.search(r',遇到嵌套 就错乱。
- 优先用非贪婪:
.*?、+改成+?、{3,}改成{3,}? - 更稳妥的是用否定字符集替代通配,例如匹配 HTML 标签内文本:用
r'([^' 而不是r'(.*)'- 调试时加
re.DEBUG标志(re.compile(pattern, re.DEBUG))能直观看到引擎如何分组和回溯re.sub() 中反向引用写错位置或转义失效
想把
'2023-12-25'换成'25/12/2023',写成re.sub(r'(\d{4})-(\d{2})-(\d{2})', r'//', s)是对的;但若写成r'//'或漏掉r前缀,就会字面替换出//。立即学习“Python免费学习笔记(深入)”;
- 反向引用只能用
\1、\2…(斜杠+数字),$1是 JavaScript/Shell 风格,Python 不认 - 如果替换字符串本身含反斜杠(如路径),务必用原始字符串
r'\\folder\\file',否则'\folder\file'会触发转义错误 - 需要动态构造替换内容时,用函数代替字符串:
re.sub(pattern, lambda m: m.group(3) + '/' + m.group(2), s),避免拼接混乱
正则真正难的不是语法,而是边界意识:你到底想“锚定在哪”、“吃掉多少”、“要不要回溯”。每次写完先用几个典型输入试,尤其关注空字符串、边界符号、嵌套结构——这些地方最容易名义上跑通,实际上漏匹配或错匹配。
- 调试时加










