Skip to main content
Documents
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

Regex (正则表达式)

官方文档: https://docs.python.org/zh-cn/3.12/library/re.html

导入方式:

import re

1. 核心 API(必须记住的 5 个)

re.match(pattern, s)      # 从开头匹配
re.search(pattern, s)     # 搜索第一个匹配
re.findall(pattern, s)    # 找出全部匹配,返回 list
re.sub(pattern, repl, s)  # 替换
re.fullmatch(pattern, s)  # 完全匹配整个字符串

2. 基本元字符

符号 含义
. 任意字符(不含换行)
\d 数字
\w 字母数字下划线
\s 空白字符
^ 开头
$ 结尾
[] 字符集
` `
() 分组

3. 数量词(非常常用)

表达式 含义
* 0 次或无限
+ 1 次或无限
? 0 或 1 次
{n} 恰好 n 次
{n,} n 次以上
{n,m} n 到 m 次

4. 常用判断示例

判断纯数字字符串

bool(re.fullmatch(r"\d+", s))

判断以 00 或 60 开头的“纯数字”

bool(re.fullmatch(r"(00|60)\d+", s))

判断邮箱格式

bool(re.fullmatch(r"[^@]+@[^@]+\.[^@]+", email))

5. 常用提取

提取所有数字

re.findall(r"\d+", text)

提取日期

re.findall(r"\d{4}-\d{2}-\d{2}", text)

提取股票代码(6 位数字)

re.findall(r"\b\d{6}\b", text)

6. 分组 (group)

m = re.search(r"(\d+)-(\d+)", "123-456")
m.group(1) # "123"
m.group(2) # "456"
m.groups() # ("123", "456")

7. 命名分组

m = re.search(r"(?P<code>\d{6})-(?P<name>\w+)", "600001-ABC")
m.group("code")
m.group("name")

8. 替换(重点)

基本替换

re.sub(r"cat", "dog", text)

替换数字为 [NUM]

re.sub(r"\d+", "[NUM]", text)

使用函数替换

def repl(m):
    return str(int(m.group()) * 2)

re.sub(r"\d+", repl, "1 2 3")
# "2 4 6"

9. compile 提升性能(生产常用)

适合大量循环匹配:

pat = re.compile(r"\d{6}")
pat.findall(text)

优势:避免多次解析正则,提高速度。

10. 非贪婪匹配

默认是贪婪:

re.findall(r"<.*>", "<a><b>")
# ['<a><b>']

非贪婪:

re.findall(r"<.*?>", "<a><b>")
# ['<a>', '<b>']

11. 前瞻 / 后顾(高级)

正向前瞻(匹配后面是某内容)

提取跟在 ¥ 后的数字:

re.findall(r"(?<=¥)\d+", "价格¥199元")

负向前瞻(后面不是某内容)

匹配不以 .jpg 结尾的文件名:

re.findall(r".+(?!\.jpg)$", filename)

12. 多行与点号匹配换行

Flags 作用
re.M ^ $ 匹配每一行的开头结尾
re.S . 匹配换行符
re.I 不区分大小写
re.X 忽略空白方便排版

示例:

re.findall(r"<div.*?</div>", html, flags=re.S)

13. 最常用正则场景总结

场景 正则
检查手机号 ^1\d{10}$
检查 email ^[^@]+@[^@]+\.[^@]+$
检查身份证 ^\d{17}[\dXx]$
全数字 ^\d+$
6 位股票代码 ^\d{6}$
以 00/60 开头股票 `^(00
日期 ^\d{4}-\d{2}-\d{2}$
提取全部中文 [\u4e00-\u9fa5]+
提取 IP \d+\.\d+\.\d+\.\d+

14. 常用的业务场景案例

股票代码过滤(标题过滤)

is_stock = bool(re.fullmatch(r"(00|60)\d+", stock_code))
has_bad_title = bool(re.search(title_exclude_regex, title))

datetime_date 替换为 datetime::date

pattern = re.compile(r"(^|\.)(datetime_date)(__|$)")
pattern.sub(r"\1datetime::date\3", source)

15. 写正则时的最佳实践

  • 使用 raw string:r"^\d+$"
  • 复杂正则先用 re.compile
  • 不确定是否匹配整个字符串用 fullmatch
  • 尽量避免过度的贪婪匹配
  • 多用命名分组提高可读性
  • 存在大量循环时一定用 compile
  • 正则太复杂时分成多个步骤