杰瑞科技汇

Python findall如何提取所有匹配结果?

re.findall() 是什么?

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

Python findall如何提取所有匹配结果?-图1
(图片来源网络,侵删)

它的核心特点是:查找所有,而不是找到第一个就停止。

基本语法

import re
re.findall(pattern, string, flags=0)

参数说明:

  • pattern: 一个字符串,表示你要匹配的正则表达式模式。
  • string: 一个字符串,表示你要在其中搜索的原始文本。
  • flags: 可选参数,用于控制正则表达式的匹配方式,例如是否忽略大小写、是否多行匹配等,我们稍后会讲到。

返回值:

  • 如果找到匹配项,返回一个列表,列表中的每个元素都是一个匹配到的字符串。
  • 如果没有找到任何匹配项,返回一个空列表 []

基本用法示例

让我们通过几个简单的例子来理解它的基本用法。

Python findall如何提取所有匹配结果?-图2
(图片来源网络,侵删)

示例 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 正则表达式的关键一步,希望这个详细的解释能帮助你彻底理解它!

分享:
扫描分享到社交APP
上一篇
下一篇