🌈个人主页:羽晨同学
💫个人格言:“成为自己未来的主人~”
上一篇文章中,我们讲到了贪婪匹配和非贪婪匹配,我们在这篇文章中,主要讲的就是贪婪匹配和非贪婪匹配的剩下的部分,话不多说,让我们开始吧。
我们先来看几个例子,大家可以相一下这个打印出来的结果是什么。
import re
print(re.findall(r"a\w+",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"\w+b",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"a\w+b",'afasfadasafa464646_fafdasda_dasdasdfb'))
这个就是打印出来的结果。
这个前面第一个正则表达式的意思是说,从a开始,中间进行贪婪匹配,直到结束。
第二个正则表达式的意思直接进行贪婪匹配,然后到b结束。
第三个正则表达式的意思是说,从a开始,中间进行贪婪匹配,然后到b结束。
你看,虽然这三个打印出来的结果是相同的,但是,其中表达的意思并不相同。
我们再来看下一个例子:
print(re.findall(r"a\w+?",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"\w+?b",'afbsfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"a\w+?b",'afbsfadasafa464646_fafdasda_dasdasdfb'))
这个是我们这次打印出来的结果,你看是不是有很大的不同。
对于贪婪匹配后面加一个?,这样子就变成了非贪婪匹配。
所以,对于第一个正则表达式而言,要找到的,是所有以a开头的字符串,并且由于是非贪婪匹配,并不无限向后找,碰到下一个a的时候,就构成了一个新的字符串。
对于第二个正则表达式而言,找到的是所有以b结尾的字符串。
对于第三个正则表达式而言,找到的是所有的以a开头,以b结尾的字符串作为元素。
我们再来看下一组表达式
print(re.findall(r"a\w*?",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"\w*?b",'afbsfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"a\w*?b",'afbsfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"a\w*",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"\w*b",'afasfadasafa464646_fafdasda_dasdasdfb'))
print(re.findall(r"a\w*b",'afasfadasafa464646_fafdasda_dasdasdfb'))
这个当中,其实需要强调的是,*表示的是0个或者多个,因为后面加上了?,所以只能找到a
我们再来看下一组代码。
import re
print(re.findall(r"\d+","fhig346-gh465464nm"))
print(re.findall(r"[a-z]+","fhig346-gh465464nm"))
# 正则1 |正则2
print(re.findall(r"\d+|[a-z]+","fhig346-gh465464nm"))
通过这个代码,我们可以了解到的是,这个|,其实就是或的意思。
我们来看下一组代码
import re
print(re.findall(r"(\d+)|[a-z]+","fhig346-gh465464nm"))
# ['', '346', '', '465464', '']
print(re.findall(r"\d+|([a-z]+)","fhig346-gh465464nm"))
print(re.findall(r"(\d+)|([a-z]+)","fhig346-gh465464nm"))
默认情况下,如果正则表达式中出现(),结合findall查找,最终的结果中只显示()的结果。这个也叫做捕获组
有捕获组,那肯定也存在着非捕获组,我们来看一下非捕获组的示例。
# b、非捕获组:(?:正则)
print(re.findall(r"(?:\d+)|[a-z]+","fhig346-gh465464nm"))
# ['fhig', '346', 'gh', '465464', 'nm']
print(re.findall(r"\d+|(?:[a-z]+)","fhig346-gh465464nm"))
# ['fhig', '346', 'gh', '465464', 'nm']
你看,这个就是非捕获组,在这种情况下面,()是不会起作用的。
练习,已知一个字符串data,检索其中合法的邮箱
data = 'yz@163.comhellodasdasda@sina.com146747@qq.com4654654@xxx.com'
import re
mall_list=re.findall(r"\w+@(?:163|126|qq|sina)\.com",data)
print(mall_list)
这样子,我们就拿到了我们想要的结果。
我们接下来讲一下正则表达式中的几个常用的函数。
1. compile():将正则字符串编译成正则对象,一般都是为了结合其他函数使用的
2. match():用正则匹配指定字符串中的内容,如果匹配上,返回Match对象
如果未匹配上,则返回None
应用:判断用户名或密码是否合法
3. search():用正则搜索指定字符串中的内容,如果匹配上,返回Match对象,如果未匹配,返回None
注意,只会查找一次
4. findall():用正则搜索指定字符串中的内容,如果匹配上,返回非空列表,如果未匹配,返回空列表
注意:查找所有
应用:全局搜索数据,在爬虫中一般使用findall
5.finditer():用正则搜索指定字符串中的内容,返回一个迭代器,
如果匹配上,则返回一个Match对象
注意,查找所有
下面,我们来写一下对应的应用这些函数的代码。
首先,我们来看第一个例子:
import re
r=re.findall(r"a\d","6a8ghjkasda3asdaa8")
print(r)
r=re.finditer(r"a\d","6a8ghjkasda3asdaa8")
print(r)
在这个打印结果当中,第一个打印出来的是字典,第二个是迭代器对象。
那我们应该怎么获取迭代器当中的数据呢?
首先,使用循环。
# 方式一
for obj in r:
print(obj)
print(obj.group()) # 获取Match对象的文本内容
# <re.Match object; span=(1, 3), match='a8'>
# a8
# <re.Match object; span=(10, 12), match='a3'>
# a3
# <re.Match object; span=(16, 18), match='a8'>
# a8
方式二,使用next.
# 方式二
print(next(r)) # <re.Match object; span=(1, 3), match='a8'>
print(next(r)) # <re.Match object; span=(10, 12), match='a3'>
print(next(r)) # <re.Match object; span=(16, 18), match='a8'>
while True:
try:
obj=next(r)
print(obj.group())
except StopIteration as e:
# 如果出现异常,则说明迭代器中的元素已经获取完毕
break
# <re.Match object; span=(1, 3), match='a8'>
# <re.Match object; span=(10, 12), match='a3'>
# <re.Match object; span=(16, 18), match='a8'>
接下来,我们来说一下split(),用正则指定的规则分割指定字符串,返回一个列表。
str1='one1two1three1four'
l1 = str1.split("1") # 字符串.split(分隔符),返回一个列表
print(l1) # ['one', 'two', 'three', 'four']
str1='one1two2three3four'
l1=re.split(r'\d+',str1) # re.split(正则分割符,字符串)
print(l1) # ['one', 'two', 'three', 'four']
l1=re.split(r'\d+',str1,2) # re.split(正则分割符,字符串,次数)
print(l1) # ['one', 'two', 'three3four']
我们接下来讲一下sub和subn
sub是将正则匹配到的子字符串用指定字符串进行替换
str1="one111two111three111four"
l1=str1.replace("111","-")
print(l1) # one-two-three-four
# 可以指定替换的次数
str2="one31324two46465three4651four"
l1=re.sub(r"\d+","-",str2)
print(l1) # one-two-three-four
str2="one31324two46465three4651four"
l1=re.sub(r"\d+","-",str2,2)
print(l1) # one-two-three4651four
而subn返回的是一个元组,格式:(新字符串,替换的次数)
str2="one31324two46465three4651four"
l1=re.subn(r"\d+","-",str2,2)
print(l1) # ('one-two-three4651four', 2)
str2="one31324two46465three4651four"
l1=re.subn(r"\d+","-",str2)
print(l1) # ('one-two-three-four', 3)
接下来,我们说一下match,search,findall之间的区别
r1=re.match(r"\d+",'as1das2')
print(r1) # None 从左往右匹配
r1=re.search(r"\d+",'as1das2')
print(r1) # <re.Match object; span=(2, 3), match='1'>
r1=re.findall(r"\d+",'as1das2')
print(r1) # ['1', '2']
注意,在正则中不要随便使用空格
print(re.search(r"\d+[a-z]+","3sdaasda-dasdad4")) # \d+ 数字可以出现一个或者多个
print(re.search(r"\d + [a-z]+","3sdaasda-dasdad4")) # \d +空格可以出现一个或者多个
flags的用法
re.I表示不区分大小写
# # flags的用法
# # re.I表示不区分大小写
print(re.split(r"a","dashjkhadAdashjkdkajaHJKHKHJAdashjkdh",re.I))
# 为了区分flasg,尽量使用关键字参数的方式给flags传参
print(re.split(r"a","dashjkhadAdashjkdkajaHJKHKHJAdashjkdh",flags=re.I))
好了,我们今天的文章就到这里,我们明天再见。