【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义

作者 : admin 本文共2570个字,预计阅读时间需要7分钟 发布时间: 2024-06-9 共2人阅读

目录

  • 问题
  • 解决方案
  • 讨论

问题

本文讨论一些按照特定的文本模式进行的查找和匹配。

解决方案

如果想要匹配的只是简单文字,通常我们使用一些内置的基本字符串方法即可,如:str.find()str.startwith()str.endswith() 或类似的函数。

text = "hello world"

match_str1 = text == 'hello world'
match_str2 = text.startswith("hello")
match_str3 = text.endswith("world")
match_str4 = text.find("w")
match_str5 = text.find("wo")
print(match_str1, match_str2, match_str3, match_str4, match_str5)

对于更为复杂的匹配则需要使用正则表达式以及 re 模块。本文中,将主要围绕 re 模块的两大函数 match() search() 以及 findall() 展开。

match()
请思考,为什么下列两个字符串中使用相同的正则化匹配结果不同?

import re

text_1 = "11/10/2023"
text_2 = "I just found my heart beat quickly from 11/10/2023, but I don't think that is love."

if re.match(r'\d+/\d+/\d+', text_1):
    print(True)
else:
    print(False)

if re.match(r'\d+/\d+/\d+', text_2):
    print(True)
else:
    print(False)

真实原因在于 re.match() 函数只在字符串的开始处进行匹配,text_1 中日期出现了开头处,但是在 text_2 中,日期在字符串的中间。

如果我们希望匹配到字符串中任何位置的日期,则应该使用 re.search() 函数。

re.search()

import re

message = "I just found my heart beat quickly from 11/10/2023, but I don't think that is love."
match = re.search(r'\d+/\d+/\d+', message)
if match:
    print("The message contains the value of date. And, the date is", match.group())
else:
    print("The message does not contain the value of date.")

结果:

【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义插图

上述代码中,通过 match.group() 方法从正则化对象 match 提取出匹配到的结果。

但是如果我们一段描述中包含多个日期内容,那么 search() 函数能够找到全部的日期内容吗?如果找不到,有什么别的函数?

findall()

import re

but = "I just found my heart beat quickly from 11/10/2023, but I don't think that is love. And now, 06/06/2024, I think it is time to put all down."
match_1 = re.search(r'\d+/\d+/\d+', but)
print("match_1:", match_1.group())
match_2 = re.findall(r'\d+/\d+/\d+', but)
print("match_2:", match_2)

结果:

【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义插图(1)

顾名思义,findall(),即 “找到所有”,其作用的确是在字符串中找到所有的满足正则化规则的值,并以列表形式返回。

print(type(match_1))
print(type(match_2))

结果:

<class 're.Match'>
<class 'list'>

明显,search() 函数的结果是正则化对象,而*findall()* 函数的结果是列表的形式。

讨论

更多的,如果我们打算对同一种模式做多次匹配,即,对很多字符串匹配同一个正则化规则,我们可以将正则表达式模式提取出来,预编译成一个模式对象。

import re

message_1 = "yesterday is 05/06/2024."
message_2 = "today is 06/06/2024."
message_3 = "tomorrow is 07/06/2024"

datepat = re.compile(r'\d+/\d+/\d+')
print(datepat.search(message_1).group())
print(datepat.search(message_2).group())
print(datepat.search(message_3).group())

更多的,读者有没有思考过,group() 函数中可以有什么参数不?

当定义正则表达式时,我们常常会将部分模式用括号包起来的方式引入捕获组。如

import re

message = "yesterday is 05/06/2024."
datepat = re.compile(r'(\d+)/(\d+)/(\d+)')

print(datepat.search(message).group())
print(datepat.search(message).group(2))

结果:

05/06/2024
2024

在正则表达式模式中,我们用 “()” 包裹了三个捕获组,对应到本样例中,即 group(1) -> ddgroup(2) -> mmgroup(3) -> yyyy

最后,\d+ 中,+ 是什么含义??

import re

pattern_1 = re.compile(r'\d')
pattern_2 = re.compile(r'\d+')

message = "我今年25岁了"
print(re.search(pattern_1, message).group())
print(re.search(pattern_2, message).group())

对比 pattern_1pattern_2 的结果,可知在正则化表达式模式中,+ 不代表数字加,不代表字符串的连结,而是代表一种“更多”的含义,在本案例中,即可以匹配 更多的 \d 整数,所以能匹配到 25,而不带 +pattern_1 只能匹配到一个数字。

本站无任何商业行为
个人在线分享 » 【Python Cookbook】S02E04 文本模式的匹配和查找 match()、search()、findall() 以及 捕获组和 + 的含义
E-->