python 正则表达式学习
python正则表达式学习
很久没有用python写正则,有些荒废,很多都忘记了,这段时间正好看了python编程书籍,算是小菜鸡的温故知新,正则表达式有很多实际的用处,然而有时候却很复杂,在用python写爬虫的时候很有用,用的好可以事半功倍,简单的回顾一下python正则表达式的一些简单用法。
创建正则表达式对象
Python 中所有正则表达式的函数都在 re 模块中。
正则表达式首先需要一个匹配模式,即你想要匹配的字符串形式,简单介绍,以匹配电话号码为例。
如下一串字符串:‘My number is 415-555-4242.’
我们想要匹配取出其中的电话号码:”415-555-4242“
首先创建一个匹配的模式:通过向re.compile()函数中传入字符串实现,字符串表示了你想要匹配的目标字符串形式,之后compile返回一个Rege对象
Regex 对象的 search()方法查找传入的字符串,寻找该正则表达式的所有匹配。如
果字符串中没有找到该正则表达式模式,search()方法将返回 None。如果找到了该模式,
search()方法将返回一个 Match 对象。Match 对象有一个 group()方法,它返回被查找字
符串中实际匹配的文本
import re
#向re.compile传入一个字符串值,表示正则表达式,返回一个Regex模式对象
phoneNumberRegex = re.compile(r'\d\d\d-\d\d\d-\d\d\d\d')
# Regex对象的search方法查找传入的字符串,如果找到了该模式,则返回一个Match对象
# Match对象中有一个group方法,会返回被查找字符串中实际匹配的文本
s = "My number is 415-555-4242"
mo = phoneNumberRegex.search(s)
print("phone number found: "+mo.group())
运行结果:
括号分组
可以在匹配模式中添加括号表示分组,如(\d\d\d)-(\d\d\d-\d\d\d\d),然后可以使用group()匹配对象方法,这里一个括号是一组,如group(1)取出第一组。
注意这里与python列表习惯不一样的是分组并不是从0开始而是从1开始,group(1)表示第一组,group(0)等价于不传入参数,返回的是整个匹配的文本。
也可以通过groups()(复数)返回匹配到的所有分组
phoneNumberRegex_1 = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
mo = phoneNumberRegex_1.search(s)
print("mo.group(0) = ",mo.group(0))
print("mo.group(1) = ",mo.group(1))
print("mo.group(2) = ",mo.group(2))
print("mo.group() = ",mo.group())
# 如果想要一次就获取所有的分组,请使用 groups()方法,注意函数名的复数形式。
#groups 返回的是一个turple数据
print("mo.groups = ",mo.groups(),type(mo.groups()))
运行结果:
管道方法匹配多个分组
字符”|“表示管道,表示选择。如模式”A|B"那么A或者B都可以被匹配,但如果A和B都在文本中,那么将会返回第一次出现的那个。
s1 = "Batman and Tina Fey is a filmaly.."
s2 = "Tina Fey and Batman is a filmaly.."
heroRegex = re.compile(r'Batman|Tina Fey')
mo1 = heroRegex.search(s1)
print("mo1.group = ",mo1.group())
# 如果 Batman 和 Tina Fey 都出现在被查找的字符串中,第一次出现的匹配文本,
# 将作为 Match 对象返回。
mo2 = heroRegex.search(s2)
print("mo2.group = ", mo2.group())
运行结果:
选择匹配
有时候我们不确定被匹配的文本是不是一定会出现,可能会出现,也可能不出现。可以用“?”实现可选匹配。
字符?表示前面的分组在这个模式中出现0此或一次。
# 用问号实现可选匹配
# 字符?表明它前面的分组在这个模式中是可选的
#注意这里的括号同样是一个分组,一样可以分组输出
batRegex = re.compile(r"Bat(wo)?man")
mo3 = batRegex.search("The Adventures of Batman")
print(mo3.group())#运行结果:Batman
mo4 = batRegex.search("The Adventures of Batwoman")
print(mo4.group())#运行结果:Batwoman
print(mo4.group(1))#运行结果:wo
多次匹配
与符号?的匹配类似,星号*表示匹配0次或者多次,这个次数不限,
加号+匹配1次或多次,类似星号*一样,只是至少匹配一次
batRegex1 = re.compile(r'Bat(wo)*man')
mo5 = batRegex1.search("The Advanture of Batman")
print(mo5.group())
mo6 = batRegex1.search("The Advanture of Batwoman")
print(mo6.group(),mo6.groups())
mo7 = batRegex1.search("The Advanture of Batwowowoman")
print(mo7.group(),mo7.groups())
运行结果:
前面的星号与加号可以给定我们匹配多次,却不能控制匹配的次数。需要指定匹配的次数或者将匹配次数控制在某一范围内,可以使用花括号{}
花括号有两种使用方法:
1、指定匹配次数。只需要传入一个指定的匹配次数,如(Ha){3}表示“Ha”重复3次,匹配“HaHaHa”,但不会匹配“Ha”,或“HaHa”等
2、指定匹配范围,类似于区间。例如(Ha){3,5}那么“Ha”重复3至5次,那么“HaHaHa”,“HaHaHaHa”,“HaHaHaHaHa”都可以被匹配。
要注意Python 的正则表达式默认是“贪心”的,这表示在有二义的情况下,它们会尽可能匹配最长的字符串。花括号的“非贪心”版本匹配尽可能最短的字符串,即在结束的花括号后跟着一个问号。
greedRegex = re.compile(r'(Ha){3,5}')#贪心匹配
mo8 = greedRegex.search("HaHaHaHaHaHaHa")
print(mo8.group())#运行结果:HaHaHaHaHa
nongreedRegex = re.compile(r'(Ha){3,5}?')#非贪心匹配
mo9 = nongreedRegex.search("HaHaHaHaHaHaHa")
print(mo9.group())#运行结果:HaHaHa
findall方法
与search方法不同,search方法只返回第一次匹配的match对象。而findall方法将返回一组字符串列表,列表中每个字符串都是一段被查找的文本。
phoneNumberRegex1 = re.compile(r"\d\d\d-\d\d\d-\d\d\d\d")
mo10 = phoneNumberRegex1.search('Cell: 415-555-9999 Work: 212-555-0000')
print(mo10.group())
# findall()不是返回一个 Match 对象,而是返回一个字符串列表
print(phoneNumberRegex1.findall('Cell: 415-555-9999 Work: 212-555-0000'))
phoneRegex2 = re.compile(r'(\d\d\d)-(\d\d\d)-(\d\d\d\d)')
print(phoneRegex2.findall('Cell: 415-555-9999 Work: 212-555-0000'))
运行结果:
415-555-9999
['415-555-9999', '212-555-0000']
[('415', '555', '9999'), ('212', '555', '0000')]
通配符
符号 . 称之为通配符,匹配除了换行符以外的所有字符。但也可以通过在compile时传入re.DOTALL参数,匹配所有字符,包括换行符。
#通配符.匹配除了换行符以外的所有字符
atRegex = re.compile(r'.at')
print(atRegex.findall('The cat in the hat sat on the flat mat.'))
# 点-星将匹配除换行外的所有字符。通过传入 re.DOTALL 作为 re.compile()的第
# 二个参数,可以让句点字符匹配所有字符,包括换行字符。
s = 'Serve the public trust.\nProtect the innocent. \nUphold the law.'
print(s)
nonewLineRegex = re.compile('.*')
print("nonlineRegex = \n",nonewLineRegex.search(s).group())
newLineRegex = re.compile('.*',re.DOTALL)
print("newlineRegex = \n",newLineRegex.search(s).group())
运行结果:
['cat', 'hat', 'sat', 'lat', 'mat']
Serve the public trust.
Protect the innocent.
Uphold the law.
nonlineRegex =
Serve the public trust.
newlineRegex =
Serve the public trust.
Protect the innocent.
Uphold the law.
以上便是小菜鸡对正则表达式的一个简单总结归纳,如有错误和疏漏,还请指正。
参考:
《ython编程快速上手—让繁琐工作自动化》,Al Sweigart 著.