re.findall() 是什么?
re.findall() 函数用于在字符串中查找所有与正则表达式模式 匹配 的子串,并以 列表 的形式返回所有匹配到的结果。

它的核心特点是:查找所有,而不是找到第一个就停止。
基本语法
import re re.findall(pattern, string, flags=0)
参数说明:
pattern: 一个字符串,表示你要匹配的正则表达式模式。string: 一个字符串,表示你要在其中搜索的原始文本。flags: 可选参数,用于控制正则表达式的匹配方式,例如是否忽略大小写、是否多行匹配等,我们稍后会讲到。
返回值:
- 如果找到匹配项,返回一个列表,列表中的每个元素都是一个匹配到的字符串。
- 如果没有找到任何匹配项,返回一个空列表
[]。
基本用法示例
让我们通过几个简单的例子来理解它的基本用法。

示例 1:查找所有出现的单词
import re
text = "The quick brown fox jumps over the lazy dog. The dog was not amused."
pattern = r"the" # 查找 "the"
# 默认情况下,re.findall() 是区分大小写的
matches = re.findall(pattern, text)
print(f"区分大小写的匹配结果: {matches}")
# 输出: 区分大小写的匹配结果: ['the'] (只匹配了第一个 "the")
# 使用 re.IGNORECASE 标志忽略大小写
matches_ignore_case = re.findall(pattern, text, re.IGNORECASE)
print(f"忽略大小写的匹配结果: {matches_ignore_case}")
# 输出: 忽略大小写的匹配结果: ['The', 'the', 'The']
说明:
r"the"是一个原始字符串,推荐在写正则表达式时使用,可以避免反斜杠\的转义问题。re.IGNORECASE(或其简写re.I) 是一个标志,告诉正则表达式引擎忽略大小写。
示例 2:查找所有数字
import re
text = "My phone number is 123-456-7890, and my ID is 98765."
pattern = r"\d+" # \d 匹配任意一个数字,+ 表示匹配前面的元素一次或多次
matches = re.findall(pattern, text)
print(f"找到的所有数字: {matches}")
# 输出: 找到的所有数字: ['123', '456', '7890', '98765']
说明:
\d是一个特殊字符,代表任意一个数字(0-9)。- 是一个量词,表示“匹配前面的元素一次或多次”。
\d+就代表“匹配一个或多个连续的数字”。
核心区别:捕获组
re.findall() 的行为会根据你的正则表达式中是否包含 捕获组 而发生根本性的变化,这是理解 findall 最关键的一点。
什么是捕获组?
用圆括号 括起来的部分就是一个捕获组,它的作用是“捕获”或“提取”这部分匹配到的内容。
模式中没有捕获组
pattern 中没有圆括号 ,re.findall() 会返回所有匹配的 完整字符串。
import re
text = "apple, banana, cherry, date"
pattern = r"\w+" # \w 匹配任意单词字符 (字母, 数字, 下划线)
# 模式没有括号,返回所有匹配的完整单词
matches = re.findall(pattern, text)
print(f"没有捕获组的结果: {matches}")
# 输出: 没有捕获组的结果: ['apple', 'banana', 'cherry', 'date']
模式中有单个捕获组
pattern 中包含一个捕获组,re.findall() 会返回一个列表,列表中是 所有被捕获组匹配到的内容,而不是整个匹配的字符串。
import re
text = "apple, banana, cherry, date"
pattern = r"(\w+)" # 模式有一个括号,捕获了单词内容
# 模式有一个括号,返回所有被括号捕获的内容
matches = re.findall(pattern, text)
print(f"单个捕获组的结果: {matches}")
# 输出: 单个捕获组的结果: ['apple', 'banana', 'cherry', 'date']
# (在这个简单例子中,结果和上面一样,但本质不同)
模式中有多个捕获组
这是最需要注意的情况! pattern 中包含多个捕获组,re.findall() 的行为会变得不同:
- 它会返回一个 元组的列表。
- 列表中的每个元组,对应一次匹配,元组中的每个元素分别对应一个捕获组匹配到的内容。
import re
text = "My phone numbers are 123-456-7890 and 987-654-3210."
# 模式有三个捕获组:(\d{3}), (\d{3}), (\d{4})
pattern = r"(\d{3})-(\d{3})-(\d{4})"
matches = re.findall(pattern, text)
print(f"多个捕获组的结果: {matches}")
# 输出: 多个捕获组的结果: [('123', '456', '7890'), ('987', '654', '3210')]
解释:
- 找到了两个匹配的完整电话号码。
- 对于第一个匹配
123-456-7890:- 第一个捕获组
(\d{3})匹配到'123'。 - 第二个捕获组
(\d{3})匹配到'456'。 - 第三个捕获组
(\d{4})匹配到'7890'。 - 所以形成一个元组
('123', '456', '7890')。
- 第一个捕获组
- 第二个匹配同理,形成
('987', '654', '3210')。 - 最终将这些元组放入一个列表中返回。
常用标志
| 标志 | 简写 | 描述 |
|---|---|---|
re.IGNORECASE |
re.I |
忽略大小写进行匹配。 |
re.MULTILINE |
re.M |
多行模式。^ 和 会匹配每行的开头和结尾,而不仅仅是整个字符串的开头和结尾。 |
re.DOTALL |
re.S |
点号 匹配包括换行符在内的所有字符。 |
示例:re.MULTILINE 的使用
import re text = """first line second line third line""" # 不使用 MULTILINE # ^ 只匹配字符串的开头 print(re.findall(r"^line", text, re.MULTILINE)) # 输出: [] (因为字符串开头是 'first') # 使用 MULTILINE # ^ 会匹配每一行的开头 print(re.findall(r"^line", text, re.MULTILINE)) # 输出: ['line'] # 同理,$ 会匹配每一行的结尾 print(re.findall(r"line$", text, re.MULTILINE)) # 输出: ['line', 'line', 'line']
re.findall() vs. re.finditer()
你可能不希望一次性得到所有匹配结果的列表,而是希望逐个处理它们,这时 re.finditer() 就派上用场了。
re.findall(): 返回一个列表,如果结果很多,会占用较多内存。re.finditer(): 返回一个迭代器,每次迭代产生一个 匹配对象,你可以从中获取详细信息(如匹配的字符串、位置等),内存效率更高。
import re
text = "apple, banana, cherry"
pattern = r"\w+"
# 使用 findall
matches_list = re.findall(pattern, text)
print(f"findall 结果: {matches_list}")
# 输出: findall 结果: ['apple', 'banana', 'cherry']
# 使用 finditer
matches_iterator = re.finditer(pattern, text)
print("\nfinditer 结果:")
for match in matches_iterator:
# match 对象包含匹配的字符串和位置信息
print(f" 匹配到: {match.group()}, 位置: {match.span()}")
# 输出:
# finditer 结果:
# 匹配到: apple, 位置: (0, 5)
# 匹配到: banana, 位置: (7, 13)
# 匹配到: cherry, 位置: (15, 21)
| 特性 | 描述 |
|---|---|
| 功能 | 在字符串中查找所有匹配正则表达式模式的子串。 |
| 返回值 | 一个列表。 |
| 关键行为 | 是否包含捕获组 决定了返回内容的格式。 |
| 无捕获组 | 返回所有匹配的 完整字符串 的列表。 |
| 单个捕获组 | 返回所有被 捕获组匹配内容 的列表。 |
| 多个捕获组 | 返回一个 元组的列表,每个元组对应一次匹配的捕获组内容。 |
| 常用标志 | re.I (忽略大小写), re.M (多行), re.S (点号匹配所有)。 |
| 替代方案 | re.finditer():返回一个迭代器,内存效率更高,适合处理大量数据。 |
掌握 re.findall() 的用法,特别是捕获组带来的不同行为,是熟练使用 Python 正则表达式的关键一步,希望这个详细的解释能帮助你彻底理解它!
