Python 正则表达式速查手册:12 个最常用的模式

站长 2026-09-29 0 约 2 分钟 453 字
#Python#正则表达式#文本处理#re

正则的本质:用模式描述文本

正则表达式(Regex)是一种描述文本模式的语言。与其说「找所有手机号」,不如用模式描述「1 开头,第二位是 3-9,后面再跟 9 个数字」——这就是正则干的事。

Python 用内置的 re 模块,零安装:

import re

text = "联系电话:13812345678,备用:19900001111"
phones = re.findall(r"1[3-9]\d{9}", text)
print(phones)  # ['13812345678', '19900001111']

四个核心函数

import re

# 1. findall:找所有匹配,返回列表
re.findall(r"\d+", "我有3个苹果和25个橘子")  # ['3', '25']

# 2. search:找第一个匹配,返回 Match 对象(没有则返回 None)
m = re.search(r"\d+", "我有3个苹果")
if m:
    print(m.group())  # '3'

# 3. sub:替换
re.sub(r"\d+", "N", "我有3个苹果和25个橘子")  # '我有N个苹果和N个橘子'

# 4. split:按模式切分
re.split(r"[,,]", "苹果,香蕉,橘子")  # ['苹果', '香蕉', '橘子']

元字符速查(正则的字母表)

符号 含义 示例
. 任意字符(除换行) a.c 匹配 abc、a1c
\d 数字 \d\d 匹配 42
\w 字母/数字/下划线 \w+ 匹配 hello_1
\s 空白(空格/制表/换行)
^ $ 行首 / 行尾 ^hello 要求行首是 hello
* 前一个出现 0 次或多次 ab* 匹配 a、ab、abbb
+ 前一个出现 1 次或多次 ab+ 匹配 ab、abbb
? 前一个出现 0 次或 1 次 colou?r 匹配 color 和 colour
{n} {n,} {n,m} 指定次数 \d{4} 恰好 4 位数字
[...] 字符集合 [aeiou] 元音之一
[^...] 排除集合 [^0-9] 非数字
(...) 分组(可提取) 见下文
A|B 或 cat|dog

大写是取反:\D 非数字,\W 非单词字符,\S 非空白。

写 Python 正则一定用原始字符串 r"...",否则 \d 会被 Python 先转义一层。

12 个实战模式(复制即用)

import re

# 1. 手机号
r"1[3-9]\d{9}"

# 2. 邮箱
r"[\w.+-]+@[\w-]+\.[\w.]+"

# 3. URL
r"https?://[\w.-]+(?:/[\w./?=&%-]*)?"

# 4. 身份证号(18位,简单校验)
r"\d{17}[\dXx]"

# 5. 日期 2026-09-29 或 2026/09/29
r"\d{4}[-/]\d{1,2}[-/]\d{1,2}"

# 6. 时间 14:30 或 14:30:05
r"\d{1,2}:\d{2}(?::\d{2})?"

# 7. IP 地址(简单版,不校验 0-255 范围)
r"(?:\d{1,3}\.){3}\d{1,3}"

# 8. 中文字符
r"[一-龥]+"

# 9. 纯数字(整数,可带负号)
r"-?\d+"

# 10. 小数(可带负号)
r"-?\d+\.?\d*"

# 11. HTML 标签
r"<[^>]+>"

# 12. 匹配汉字开头的用户名(2-6位中文或数字字母)
r"^[一-龥][\w一-龥]{1,5}$"

分组提取:不只匹配,还要拿出来

圆括号 () 分组后,可以分别提取每部分内容:

import re

log = "2026-09-29 14:30:05 [ERROR] 数据库连接失败"

# 三个分组:日期、时间、日志内容
pattern = r"(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) \[(\w+)\] (.+)"
m = re.search(pattern, log)
if m:
    date, time_, level, msg = m.groups()
    print(date, time_, level, msg)  # 2026-09-29 14:30:05 ERROR 数据库连接失败

命名分组更可读:

pattern = r"(?P<date>\d{4}-\d{2}-\d{2}) (?P<time>\d{2}:\d{2}:\d{2}) \[(?P<level>\w+)\] (?P<msg>.+)"
m = re.search(pattern, log)
print(m.group("msg"))  # 按名字取,不用数括号顺序

贪婪与非贪婪:最容易踩的坑

默认是贪婪匹配——尽可能多地吃字符:

import re

text = "<p>第一段</p><p>第二段</p>"

# 贪婪:从第一个 <p> 一直吃到最后一个 </p>
re.findall(r"<p>.*</p>", text)
# ['<p>第一段</p><p>第二段</p>']  ← 不是想要的!

# 非贪婪(加 ?):吃到最近的 </p> 就停
re.findall(r"<p>.*?</p>", text)
# ['<p>第一段</p>', '<p>第二段</p>']  ← 正确

记住:*、+、{n,m} 后面加 ? 就变非贪婪。解析 HTML/括号配对内容时,几乎总是用非贪婪。

编译复用与标志位

循环里反复用同一个正则,先编译一次提速:

PHONE_RE = re.compile(r"1[3-9]\d{9}")  # 编译一次
for line in lines:
    m = PHONE_RE.search(line)           # 复用

常用标志位:

re.findall(r"hello", text, re.IGNORECASE)  # 忽略大小写,HELLO 也能匹配
re.findall(r"^第.章", text, re.MULTILINE)  # 多行模式:^ $ 匹配每行的首尾
re.findall(r"a.c", text, re.DOTALL)        # 让 . 也能匹配换行符

什么时候不该用正则

正则很强,但有边界:

  1. 别用正则解析 HTML:HTML 不是规则语言,嵌套和异常写法会让正则崩溃。用 BeautifulSoup/lxml
  2. 别用正则校验复杂规则:密码强度「同时含大小写+数字+符号且不复读」,用代码逐项判断比一条超长正则清晰得多
  3. 简单字符串操作别上正则:s.startswith()、s.split()、in 能解决的,用它们更快更易读

练习与调试工具

  • regex101.com:在线调试神器,粘贴文本和正则,实时高亮匹配、逐字符解释正则含义
  • pythex.org:轻量替代
  • 写复杂正则时,先写 3-5 个「应该匹配」和「不应该匹配」的测试用例,边写边验证

写在最后

正则不用「学会」再开始用——它是个查表工具。收藏本文的 12 个模式,遇到新需求时在 regex101 上边试边改,三次之后你就会发现自己已经不怎么看表了。

评论 (0)

我的头像

还没有评论,快来抢沙发吧~