参考:正则表达式指南 — Python 3.14.0 文档

正则表达式(Regular expressions,也叫 REs、 regexs 或 regex patterns),本质上是嵌入 Python 内部并通过 re 模块提供的一种微小的、高度专业化的编程语言。使用这种小语言,你可以为想要匹配的可能字符串编写规则;这些字符串可能是英文句子、邮箱地址、TeX 命令或任何你喜欢的内容。然后,你可以提出诸如“此字符串是否与表达式匹配?”、“字符串中是否存在表达式的匹配项?”之类的问题。你还可以用正则来修改字符串,或以各种方式将其拆分

正则表达式会被编译成一系列字节码,然后由 C 语言编写的匹配引擎执行。对于高级用途,可能有必要特别注意引擎将如何执行一个给定的正则,并以某种方式写入正则,以生成运行更快的字节码。本文不涉及优化问题,因为这要求你对正则引擎的匹配过程有很好的了解。

正则表达式语言相对较小且受限,因此并非所有可能的字符串处理任务都可以使用正则表达式完成。有些任务尽管 可以 用正则表达式来完成,但表达式会变得非常复杂。 这些情况下,最好通过编写 Python 代码来进行处理。 也许 Python 代码会比精心设计的正则表达式慢,但它可能更容易理解。

正则表达式是一种小型、专用的语言,用来匹配字符串模式。可以用它做三件事:

  1. 判断字符串是否符合模式

  2. 查找字符串中符合模式的部分

  3. 替换、拆分字符串

1:基本字符匹配

  • 普通字符匹配自身,例如 'test' 匹配字符串 'test'

  • 元字符(特殊字符,不直接匹配自身,这些是比较特殊的字符,用于控制匹配的模式):

    #有点多,看一遍感觉就行了😀
    . ^ $ * + ? { } [ ] \ | ( )
    . (点号)
    匹配除换行符(\n)外的任意单个字符(re.DOTALL 可以匹配换行符)
    示例:a.b 匹配 "aab", "a1b", "a b" 等
    ​
    ^ (脱字符)
    匹配字符串的开始位置
    示例:^abc 匹配以 "abc" 开头的字符串
    ​
    $ (美元符)
    匹配字符串的结束位置
    示例:xyz$ 匹配以 "xyz" 结尾的字符串
    ​
    \ (反斜杠)
    转义字符,使后面的字符失去特殊含义
    示例:\. 匹配实际的点号而不是任意字符
    ​
    [] (方括号)
    定义字符集合,匹配其中任意一个字符
    示例:[aeiou] 匹配任意一个元音字母
    ​
    [^] (否定字符类)
    匹配不在方括号中的任意字符
    示例:[^0-9] 匹配任意非数字字符
    ​
    - (连字符)
    在字符类中表示范围
    示例:[a-z] 匹配任意小写字母
    ​
    * (星号)
    匹配前面的子表达式(字符)零次或多次
    示例:ab*c 匹配 "ac", "abc", "abbc" 等
    ​
    + (加号)
    匹配前面的子表达(字符)式一次或多次
    示例:ab+c 匹配 "abc", "abbc" 但不匹配 "ac"
    ​
    ? (问号)
    匹配前面的子表达式零次或一次
    示例:colou?r 匹配 "color" 和 "colour"
    ​
    {n} (花括号)
    精确匹配n次
    示例:a{3} 匹配 "aaa"
    ​
    {n,}
    至少匹配n次
    示例:a{2,} 匹配 "aa", "aaa" 等
    ​
    {n,m}
    匹配n到m次
    示例:a{2,4} 匹配 "aa", "aaa", "aaaa"
    ​
    () (圆括号)
    定义子表达式或捕获组
    示例:(ab)+ 匹配 "ab", "abab" 等
    ​
    | (竖线)
    表示"或"关系
    示例:cat|dog 匹配 "cat" 或 "dog"
    ​
    \d
    匹配任意数字,等价于 [0-9]
    ​
    \D(大写)
    匹配任意非数字,等价于 [^0-9]
    ​
    \w
    匹配任意单词字符(字母、数字、下划线),等价于 [a-zA-Z0-9_]
    ​
    \W(大写)
    匹配任意非单词字符,等价于 [^a-zA-Z0-9_]
    ​
    \s
    匹配任意空白字符(空格、制表符、换行符等)
    ​
    \S(大写)
    匹配任意非空白字符
    ​
    \b
    匹配单词边界
    示例:\bcat\b 匹配 "cat" 但不匹配 "category"
    ​
    \B
    匹配非单词边界(也就是这是个词中的一个片段)
    示例:\Bcat\B 匹配 "scattered" 中的 "cat" 但不匹配单独的 "cat"
    ​
    \n
    匹配换行符
    ​
    \t
    匹配制表符
    ​
    \r
    匹配回车符
    ​
    \f
    匹配换页符
    ​
    \v
    匹配垂直制表符
    ​
    #默认情况下,量词(*, +, ?, {})是贪婪的,会尽可能多地匹配字符。在量词后加?可使其变为非贪婪(懒惰)模式:
    *?:零次或多次,但尽可能少
    +?:一次或多次,但尽可能少
    ??:零次或一次,但尽可能少
    {n,m}?:n到m次,但尽可能少
    示例:<.*?> 匹配HTML标签时不会跨标签匹配
    ​
    (?=...) (正向肯定预查)
    匹配后面跟着特定模式的位置
    示例:Windows(?=95|98) 匹配后面跟着95或98的"Windows"
    ​
    (?!...) (正向否定预查)
    匹配后面不跟着特定模式的位置
    示例:Windows(?!95|98) 匹配后面不跟着95或98的"Windows"
    ​
    (?<=...) (反向肯定预查)
    匹配前面是特定模式的位置
    示例:(?<=95|98)Windows 匹配前面是95或98的"Windows"
    ​
    (?<!...) (反向否定预查)
    匹配前面不是特定模式的位置
    示例:(?<!95|98)Windows 匹配前面不是95或98的"Windows"

2:Python中使用正则

re模块是python自带的模块,不需要额外的安装。先看一下都有哪些用法,掌握一些必要的核心的函数。

函数名 作用 参数及含义 返回值
re.match(pattern, string, flags=0) 从字符串开头匹配正则表达式 - pattern:正则表达式 - string:目标字符串 - flags(可选):匹配模式,如 re.I, re.M, re.S 匹配成功:Match 对象 匹配失败:None
re.search(pattern, string, flags=0) 在整个字符串中搜索第一个匹配项 re.match 相同 匹配成功:Match 对象 匹配失败:None
re.findall(pattern, string, flags=0) 返回字符串中所有匹配项 re.match 相同 列表,包含所有匹配子串; 无匹配返回 []
re.finditer(pattern, string, flags=0) 返回字符串中所有匹配项的迭代器 re.match 相同 迭代器,每个元素是 Match 对象; 无匹配迭代为空
re.split(pattern, string, maxsplit=0, flags=0) 根据正则表达式分割字符串 - pattern:正则表达式 - string:目标字符串 - maxsplit(可选):最大分割次数,0 表示不限 - flags(可选):匹配模式 列表,包含分割后的子串
re.sub(pattern, repl, string, count=0, flags=0) 使用 repl 替换匹配部分 - pattern:正则表达式 - repl:替换字符串或函数 - string:目标字符串 - count(可选):替换次数,0 表示全部 - flags(可选):匹配模式 返回替换后的新字符串
re.subn(pattern, repl, string, count=0, flags=0) re.sub 类似,但返回替换次数 参数与 re.sub 相同 返回 (new_string, 替换次数) 的元组
re.compile(pattern, flags=0) 编译正则表达式,生成 Pattern 对象 - pattern:正则表达式 - flags(可选):匹配模式 返回 Pattern 对象,可调用 .match(), .search(), .findall(), .split(), .sub()

匹配模式:

匹配模式(flags) 作用 示例 说明
re.Ire.IGNORECASE 忽略大小写匹配 re.match(r'abc', 'ABC', re.I) → 匹配成功 'a' 可以匹配 'A'
re.Mre.MULTILINE 多行模式:^$ 匹配每一行的开头和结尾 re.findall(r'^a', 'a\nb\na', re.M)['a', 'a'] 默认情况下,^$ 只匹配整个字符串的开头和结尾
re.Sre.DOTALL 使 . 匹配换行符 \n re.findall(r'.+', 'a\nb', re.S)['a\nb'] 默认情况下,. 不匹配换行符
re.Xre.VERBOSE 允许正则表达式写成多行并加注释 re.compile(r""" \d+ # 匹配数字 """, re.X) 便于阅读复杂正则表达式
re.Are.ASCII 只匹配 ASCII 字符,\w, \b 等只匹配 ASCII re.findall(r'\w+', 'café', re.A)['caf'] 非 ASCII 字符(如 'é')不会匹配
re.Lre.LOCALE 依赖当前区域设置的字符分类 根据系统 locale 对字符分类处理 一般不常用,依赖操作系统语言环境
re.Ure.UNICODE 以 Unicode 方式匹配 \w, \b 默认 Python3 已开启 在 Python3 默认启用 Unicode 支持
re.T 匹配方式不常用(弃用) 现代 Python 中一般不用
flags=0 表示没有启用任何模式 默认匹配:区分大小写,. 不匹配换行符,^$ 匹配整个字符串开头和结尾,不启用多行、多行注释或其他特殊行为
方法 参数 作用 详细说明
group([n]) n 可选,整数或多个整数 返回匹配的子串或指定捕获组 - 如果不传 n,返回整个匹配字符串,即正则匹配的完整内容 - 如果传 n,返回第 n 个捕获组(从 1 开始,0 是整个匹配) - 可以传多个参数,如 m.group(1,2) 返回一个元组
groups(default=None) default 可选,默认 None 返回所有捕获组组成的元组 - 捕获组就是正则中用 () 包起来的部分 - 返回的顺序和正则里括号的顺序一致 - 如果某个捕获组没有匹配,则返回 default
groupdict(default=None) default 可选,默认 None 返回命名捕获组组成的字典 - 捕获组如果使用 (?P<name>...) 命名,则可以通过字典获取 - 没匹配到的组会返回 `default
start([group]) group 可选,整数 返回匹配或捕获组的起始索引(字符串位置) - 索引从 0 开始 - 默认返回整个匹配的起始位置 - 如果传 group,返回该捕获组在原字符串的起始位置
end([group]) group 可选,整数 返回匹配或捕获组的结束索引(不包括该位置字符) - 结束索引是 右开区间,即不包含该位置 - 默认返回整个匹配的结束位置 - 如果传 group,返回该捕获组结束位置
span([group]) group 可选,整数 返回 (start, end) 元组 - 其实就是同时返回 start()end() - 默认返回整个匹配的区间 - 如果传 group,返回该捕获组的区间
import re
​
# 示例字符串
text = "abc123"
​
# 正则里有两个捕获组:
# 第一个 (\w+) 代表匹配字母部分
# 第二个 (\d+) 代表匹配数字部分
m = re.match(r'(\w+)(\d+)', text)
​
# =====================================================
# 1️⃣ group([n]):返回匹配的子串或指定捕获组
# =====================================================
​
# 不传参数,返回整个匹配到的内容
print("m.group()     ->", m.group())      # 'abc123'
​
# group(0) 永远是整个匹配结果(等价于不传参数)
print("m.group(0)    ->", m.group(0))     # 'abc123'
​
# group(1) 返回第1个捕获组(第一个括号)
print("m.group(1)    ->", m.group(1))     # 'abc'
​
# group(2) 返回第2个捕获组(第二个括号)
print("m.group(2)    ->", m.group(2))     # '123'
​
# 可以一次取多个捕获组,返回元组
print("m.group(1, 2) ->", m.group(1, 2))  # ('abc', '123')
​
​
# =====================================================
# 2️⃣ groups(default=None):返回所有捕获组的元组
# =====================================================
​
m2 = re.match(r'(\w+)(\d+)?', "abc")  # 第二组是可选的 '?'
​
print("\nm2.groups()            ->", m2.groups())           
# 输出 ('abc', None),因为第二个捕获组 (\d+) 没匹配到
​
print("m2.groups(default='0') ->", m2.groups(default='0')) 
# 输出 ('abc', '0'),用 default 替换 None
​
​
# =====================================================
# 3️⃣ groupdict(default=None):返回命名捕获组的字典
# =====================================================
​
# 使用 (?P<name>...) 定义命名捕获组
m3 = re.match(r'(?P<word>\w+)(?P<num>\d+)?', "abc")
​
print("\nm3.groupdict()           ->", m3.groupdict())        
# {'word': 'abc', 'num': None}
​
print("m3.groupdict(default='0') ->", m3.groupdict(default='0')) 
# {'word': 'abc', 'num': '0'}
​
# 命名捕获组还可以直接通过 group('name') 访问
print("m3.group('word') ->", m3.group('word'))  # 'abc'
​
​
# =====================================================
# 4️⃣ start([group]):返回匹配或捕获组的起始索引
# =====================================================
​
print("\nm.start()   ->", m.start())    # 0,整个匹配的起始位置
print("m.start(1)  ->", m.start(1))    # 0,第1组 'abc' 的起始
print("m.start(2)  ->", m.start(2))    # 3,第2组 '123' 的起始
​
​
# =====================================================
# 5️⃣ end([group]):返回匹配或捕获组的结束索引(不含该位置)
# =====================================================
​
print("\nm.end()   ->", m.end())    # 6,整个匹配结束位置
print("m.end(1)  ->", m.end(1))    # 3,第1组 'abc' 结束
print("m.end(2)  ->", m.end(2))    # 6,第2组 '123' 结束
​
​
# =====================================================
# 6️⃣ span([group]):返回 (start, end) 元组
# =====================================================
​
print("\nm.span()   ->", m.span())    # (0, 6),整个匹配区间
print("m.span(1)  ->", m.span(1))    # (0, 3),第1组区间
print("m.span(2)  ->", m.span(2))    # (3, 6),第2组区间
​
# 你可以用 span 结果在原字符串中切片取出对应部分
start, end = m.span(1)
print("text[start:end] ->", text[start:end])  # 'abc'
​

有了上边的“字典”就可以开始使用正则表达式了。上手试试。

1. re.match()-从头匹配

import re
​
text = "python is great"
m = re.match(r"python", text)
if m:  #在这里,当匹配的时候,如果匹配的是空那么是会返回None的。因此这里就是匹配是否是空,如果不是空(也就是True)
    print(m.group())  #返回匹配的子串或指定捕获组
    print(m.span())  #返回start end 的元组。
#python
#(0, 6)

2.re.search()-找第一个匹配的

import re
text1 = "i love python and python"
m = re.search(r"python", text1, re.IGNORECASE)
print(m.group())
print(m.start(), m.end())
​
#python
#7 13

3.re.findall() - 找所有匹配(返回列表)

text2 = "Emails: alice@163.com, bob@gmail.com, eve@outlook.com"
email = re.findall(r'\w+@\w+\.\w+', text2)  #\w匹配任意单词字符(字母、数字、下划线)
#\w+匹配一个或多个“单词字符” (字母、数字、下划线)
print(email)
​

4.re.finditer() —— 迭代器版 findall(带位置)

for m in re.finditer(r'\d+', "age:18, score:95, id:007"):
    print(f"找到数字:{m.group()}在位置{m.span()}")
​
#找到数字:18在位置(4, 6)
#找到数字:95在位置(14, 16)
#找到数字:007在位置(21, 24)

5.re.sub() —— 替换

text3 = "my phone is 123-123-4256"
clean = re.sub(r'\d{3}-\d{3}-\d{4}','[PHONE]', text3)  #\d{} 匹配数字
#re.sub(pattern, repl, string, count=0, flags=0) 在字符串 string 中查找所有匹配 pattern 的部分,并把它们替换为 repl。。
print(clean)

6.re.split() —— 正则分割

text4 = "apple, banban; orange grape"
items = re.split(r'[,;]\s*', text4) #[,;]\s*  一个逗号或分号,后面可带任意数量的空格
#re.split(pattern, string, maxsplit=0, flags=0)--按正则匹配的内容来切割字符串,返回一个列表。
print(items)
#['apple', 'banban', 'orange grape']

7.re.compile() —— 预编译-不用每次在从新写正则表达式了

pattern = re.compile(r'\d{4}-\d{2}-\d{2}')
dates = ["2025-11-12", "invalid", "2066-01-01"]
for s in dates:
    if pattern.match(s):
        print(s,"是合法的日期格式")
​
#2025-11-12 是合法的日期格式
#2066-01-01 是合法的日期格式

ending - 感觉够用了,遇到再麻烦的话就直接上大模型了。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐