Regex (正则表达式)
官方文档: https://docs.python.org/zh-cn/3.12/library/re.html
导入方式:
import re
re.match(pattern, s) # 从开头匹配
re.search(pattern, s) # 搜索第一个匹配
re.findall(pattern, s) # 找出全部匹配,返回 list
re.sub(pattern, repl, s) # 替换
re.fullmatch(pattern, s) # 完全匹配整个字符串
| 符号 | 含义 |
|---|---|
| . | 任意字符(不含换行) |
| \d | 数字 |
| \w | 字母数字下划线 |
| \s | 空白字符 |
| ^ | 开头 |
| $ | 结尾 |
| [] | 字符集 |
| ` | ` |
| () | 分组 |
| 表达式 | 含义 |
|---|---|
| * | 0 次或无限 |
| + | 1 次或无限 |
| ? | 0 或 1 次 |
| {n} | 恰好 n 次 |
| {n,} | n 次以上 |
| {n,m} | n 到 m 次 |
bool(re.fullmatch(r"\d+", s))
bool(re.fullmatch(r"(00|60)\d+", s))
bool(re.fullmatch(r"[^@]+@[^@]+\.[^@]+", email))
re.findall(r"\d+", text)
re.findall(r"\d{4}-\d{2}-\d{2}", text)
re.findall(r"\b\d{6}\b", text)
m = re.search(r"(\d+)-(\d+)", "123-456")
m.group(1) # "123"
m.group(2) # "456"
m.groups() # ("123", "456")
m = re.search(r"(?P<code>\d{6})-(?P<name>\w+)", "600001-ABC")
m.group("code")
m.group("name")
re.sub(r"cat", "dog", text)
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"
适合大量循环匹配:
pat = re.compile(r"\d{6}")
pat.findall(text)
优势:避免多次解析正则,提高速度。
默认是贪婪:
re.findall(r"<.*>", "<a><b>")
# ['<a><b>']
非贪婪:
re.findall(r"<.*?>", "<a><b>")
# ['<a>', '<b>']
提取跟在 ¥ 后的数字:
re.findall(r"(?<=¥)\d+", "价格¥199元")
匹配不以 .jpg 结尾的文件名:
re.findall(r".+(?!\.jpg)$", filename)
| Flags | 作用 |
|---|---|
| re.M | ^ $ 匹配每一行的开头结尾 |
| re.S | . 匹配换行符 |
| re.I | 不区分大小写 |
| re.X | 忽略空白方便排版 |
示例:
re.findall(r"<div.*?</div>", html, flags=re.S)
| 场景 | 正则 |
|---|---|
| 检查手机号 | ^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+ |
is_stock = bool(re.fullmatch(r"(00|60)\d+", stock_code))
has_bad_title = bool(re.search(title_exclude_regex, title))
pattern = re.compile(r"(^|\.)(datetime_date)(__|$)")
pattern.sub(r"\1datetime::date\3", source)
- 使用 raw string:
r"^\d+$" - 复杂正则先用 re.compile
- 不确定是否匹配整个字符串用 fullmatch
- 尽量避免过度的贪婪匹配
- 多用命名分组提高可读性
- 存在大量循环时一定用 compile
- 正则太复杂时分成多个步骤