目录
- 问题
- 解决方案
- 讨论
问题
本文讨论一些按照特定的文本模式进行的查找和匹配。
解决方案
如果想要匹配的只是简单文字,通常我们使用一些内置的基本字符串方法即可,如: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.")
结果:
上述代码中,通过 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)
结果:
顾名思义,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) -> dd
,group(2) -> mm
,group(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_1
与 pattern_2
的结果,可知在正则化表达式模式中,+
不代表数字加,不代表字符串的连结,而是代表一种“更多”的含义,在本案例中,即可以匹配 更多的 \d
整数,所以能匹配到 25
,而不带 +
的 pattern_1
只能匹配到一个数字。