1、简单介绍
正则表达式,简称regex,是文本模式的描述方法。例如:\d是一个正则表达式,表示一位数字字符,即任何一位0-9的数字。
Python中所有正则表达式的函数都在 re 模块中。在交互环境中输入以下代码,导入该模块
import re
2、用正则表达式查找文本模式
2.1创建正则表达式和匹配Regex对象
向 re.compile() 传入一个字符串值,表示正则表达式,它将返回一个Regex 模式对象。Regex对象的 search() 方法查找传入的字符串,寻找该正则表达式的所有匹配,如果字符串中没有找到该正则表达式模式, search() 方法将返回None。如果找到了, search() 方法将返回一个Match 对象。Match 对象有一个 group()方法,它返回被查找字符串中实际匹配的文本。例子:
import re
phoneNumRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo = phoneNumRegex.search('My number is 415-596-4565')
print(f"Phone number found: {mo.group()}")
输出结果:
Phone number found: 415-596-4565
2.2正则表达式匹配要点总结
在Python中使用正则表达式有几个步骤:
1.用 import re 导入正则表示模块
2.用 re.compile() 函数创建一个Regex对象(记得使用原始字符串)
3.向Regex 对象的 search()方法传入想查找的字符串。它返回一个Match对象.
4.调用Match对象的group()方法,返回实际匹配文本的字符串。
3.用正则表达式匹配更多模式
3.1用括号分组
若想将区号从电话号码中分离出来。添加括号将在正则表达式中创建“分组”:(\d\d\d)-(\d\d\d-\d\d\d\d)。然后使用 group()匹配对象方法,从一个分组中获取匹配的文本。
正则表达式字符串中的第一对括号是第1组。第二对括号是第2组。向group()传入0或不传入参数,将返回整个匹配的文本。如果想要一次就获取所有的分组,请使用 groups()方法
例子:
import re
phoneNumRegex = re.compile(r'(\d\d\d)-(\d\d\d-\d\d\d\d)')
mo = phoneNumRegex.search('My number is 415-596-4565')
print(mo.group(0))
print(mo.group(1))
print(mo.group(2))
print(mo.groups())
areaCode, mainNumber = mo.groups()
print(f"{areaCode}-{mainNumber}")
输出结果:
415-596-4565
415
596-4565
('415', '596-4565')
415-596-4565
3.2用管道匹配多个分组
字符 | 称为“管道”。希望匹配许多表达式中的一个时。就可以使用它。例如,正则表达式:r'Batman|Tina Fey'将匹配‘Batman’或‘Tina Fey’。
如果Batman和Tina Fey都出现在被查找的字符串中,第一次出现的匹配文本,将作为Match对象返回。
import re
heroRegex = re.compile(r'Batman|Tina Fey')
mo1 = heroRegex.search('Batman and Tina Fey')
mo2 = heroRegex.search('Tina Fey and Batman')
print(mo1.group())
print(mo2.group())
运行结果:
Batman
Tina Fey
---------------------------------------------------------------------------------------------------------------------------------
如果你希望匹配 'Batman'、'Batmobile'、'Batcopter'和'Batbat'中任意一个。因为所有这些字符串都以Bat开始,所以如果能够只指定一次前缀,就很方便。
import re
batRegex = re.compile(r'Bat(man|mobile|copter|bat)')
mo = batRegex.search('Batmobile lost a wheel')
print(mo.group())
print(mo.group(1))
运行结果
Batmobile
mobile
3.3用问号实现可选匹配
有时候,想匹配的模式是可选的。就是说,不论这段文本在不在,正则表达式都会认为匹配。字符?表明它前面的分组在这个模式中是可选的。
例子1:
import re
batRegex = re.compile(r'Bat(wo)?man')
mo1 = batRegex.search('The Adventures of Batman')
mo2 = batRegex.search('The Adventures of Batwoman')
print(mo1.group())
print(mo2.group())
运行结果:
Batman
Batwoman
利用前面电话号码的例子,可以让正则表达式寻找包含区号或不包含区号的电话号码
import re
phoneRegex = re.compile(r'(\d\d\d-)?(\d\d\d-\d\d\d\d)')
mo1 = phoneRegex.search('My number is 415-555-4242')
mo2 = phoneRegex.search('My name is 555-4242')
print(mo1.group())
print(mo2.group())
运行结果:
415-555-4242
555-4242
3.4用 * 号匹配零次或多次
* (星号)意味着”匹配零次或多次“,即星号之前的分组,可以在文本中出现任一次。它可以完全不存在,或一次又一次的重复。
import re
batRegex = re.compile(r'Bat(wo)*man')
mo1 = batRegex.search("The Adventures of Batman")
mo2 = batRegex.search("The Adventures of Batwoman")
mo3 = batRegex.search("The Adventures of Batwowowoman")
print(mo1.group())
print(mo2.group())
print(mo3.group())
运行结果:
Batman
Batwoman
Batwowowoman
3.5用加号匹配一次或多次
* 号意味着”匹配零次或多次“,+(加号)则意味着”匹配一次或多次“。星号不要求分组出现在匹配的字符串中,但加号不同,加号前面的分组必须”至少出现一次“,这不是可选的。
import re
batRegex = re.compile(r'Bat(wo)+man')
mo1 = batRegex.search('The Adventures of Batwoman')
mo2 = batRegex.search('The Adventures of Batwowowoman')
print(mo1.group())
print(mo2.group())
运行结果:
Batwoman
Batwowowoman
正则表达式Bat(wo)+man 不会匹配字符串‘The Adventures of Batman’,因为加号要求 wo 至少出现一次。
3.6 用花括号匹配字符串
如果想要一个分组重复特定次数,就在正则表达式中该分组的后面,跟上花括号包围的数字,例如,正则表达式(Ha){3}将匹配字符串‘HaHaHa’.
除了一个数字,还可以指定一个范围,即在花括号中写下一个最小值、一个逗号和一个最大值。例如,正则表达式(Ha){3,5}将匹配字符串‘HaHaHa’、‘HaHaHaHa’和‘HaHaHaHaHa’
也可以不写花括号中的第一个或第二个数字,不限定最小值或最大值。例如:正则表达式(Ha){3,}将匹配3次或更多次实例,正则表达式(Ha){,5}将匹配0到5次实例
3.7 贪心和非贪心匹配
在字符串'HaHaHaHaHa'中,因为(Ha){3,5}可以匹配3个、4个或5个实例,你可能会有疑问,为什么在前面花括号的例子中,Match对象group()调用会返回'HaHaHaHaHa',而不是更短的可能结果。比较‘HaHaHa’和‘HaHaHaHa’也能有效匹配正则表达式(Ha){3,5}。
python 的正则表达式默认是“贪心”的,这表示在有二义性的情况下,他们尽可能匹配最长的字符串。花括号的“非贪心”版本匹配尽可能最短的字符串,即在结束的花括号后跟着一个问号。
import re
greedyHaRegex = re.compile(r'(Ha){3,5}')
nongreedyHaRegex = re.compile(r'(Ha){3,5}?')
mo1 = greedyHaRegex.search("HaHaHaHaHa")
mo2 = nongreedyHaRegex.search("HaHaHaHaHa")
print(mo1.group())
print(mo2.group())
运行结果:
HaHaHaHaHa
HaHaHa
注意,问号在正则表达式中肯有两种含义:声明非贪心匹配或表示可选分组,这两种含义是完全无关的。
4. findall()方法
search()方法只能返回一个Match对象,包含被查找字符串中第一次匹配的文本,而findall()方法返回一组字符串,包含被查找字符串中的所有匹配。
另外,findall()方法不是返回一个Match,而是返回一个字符串列表,只要在正则表达式中没有分组。如果在正则表达式中有分组,那么findall()方法将返回元组的列表。
import re
phoneRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
mo1 = phoneRegex.search('My number is 415-555-4242 and 212-425-3666')
mo2 = phoneRegex.findall('My number is 415-555-4242 and 212-425-3666')
phoneRegex = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
mo3 = phoneRegex.findall('My number is 415-555-4242 and 212-425-3666')
print(mo1.group())
print(mo2)
print(mo3)
输出结果:
415-555-4242
['415-555-4242', '212-425-3666']
[('415', '555', '4242'), ('212', '425', '3666')]