正则表达式篇
- 过滤必要信息
- 数据清洗
python中正则表达式的应用
python中通过re模块来进行使用正则表达式
主要实现流程为
import re
#使用match方法进行匹配操作
result =re.match(正则表达式,要匹配的字符串)
#如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()
match的语法 re.match(r"Hello","Hello word")
前面必须要加一个r
正则表达式简而言之分为以下几个部分
- 匹配单个字符
- 匹配多个字符
- 匹配开头结尾
- 匹配分组
首先先了解匹配单个字符的规则
匹配单个字符
字符 | 功能 |
---|---|
. | 匹配任意一个字符(除了\n) |
[] | 匹配[]中列举的字符 |
\d | 匹配数字即 0-9 |
\D | 匹配非数字 即不是数字 |
\s | 匹配空白即空格或 tab键 |
\S | 匹配非空白字符 |
\w | 匹配单词字符,即a-z ,A-Z , 0-9, _ |
\W | 匹配非单词字符 |
匹配连续数据
import re
re.match(r"速度与激情[1-9]","速度与激情8").group()
我们也可以进行分块匹配非连续数据
import re
re.match(r"速度与激情[1-36-9]","速度与激情8").group()
我们如果要想匹配带字母的和数字混合的
import re
re.match(r"速度与激情[1-8abcd]","速度与激情a").group()
在连续/非连续数据上加入想要匹配的单个字符/连续字符
import re
re.match(r"速度与激情[1-8a-z]","速度与激情g").group()
这里需要注意的是,在正则匹配中,严格区分大小写
import re
re.match(r"速度与激情[1-8a-zA-Z]","速度与激情G").group()
这里单一匹配显得很low,我们可以通过匹配的法则来进行定向匹配
import re
re.match("速度与激情\w","速度与激情_").group()
>>速度与激情_
匹配规则匹配数字
import re
re.match("速度与激情\d","速度与激情4").group()
>>速度与激情4
\w
可以匹配任意字符,包括下划线 _
\d
匹配任意数字
\s
匹配空白字符或者tab键(用的比较少)
.
点就比较牛的,可以匹配任意字符
匹配多个字符(配合其他规则执行进行匹配的)
字符 | 功能 |
---|---|
* | 匹配前一个字符出现出现0次或者无限次,即可有可无 |
+ | 匹配前一个字符出现一次或者无限次,即至少1次 |
? | 匹配前一个字符出现1次或者0次,即要么一次要么没有 |
{m} | 匹配前一个字符串出现m次 |
{m,n} | 匹配前一个字符串出现从m到n次 |
示例:
需求:匹配出一个字符第一个字母为大小写字符,后面都是小写字母并且这些小写字母可有可无
import re
ret =re.match("[A-Z][a-z]*","N")
print(ret.group())
>>N
如果我要是想匹配一个/两个的话,不确定是几,那么我们就需要用到正则规则来进行编写
import re
re.match("速度与激情\d{1,2}","速度与激情14").group()
解释一下上述代码,对于\d
来说,他是匹配数字的正则规则,对于后面的{}
它的实际意义是作用于前面的 \d
意思是判断有一个数字或者两个数字都行 {1,2}
代表的就是1/2数字要是 {1,3}
的话就是三位数也行
应用场景:一般这种正则规则都应用在网站注册界面,比如我指定判断为11位的手机号
import re
re.match("\d{11}","12345678901").group()
如果中间有空格也不行大括号无论前面是什么,作用的都是前面的东西 比如 速度与激情a{1,3} 那么匹配速度与激情a/速度与激情aa/速度与激情aaa均可成功匹配
我对 {}
中的 ,
理解是,里面相当于或,什么都行的意思,这个可以,那个也可以,直至规则限定数字,而不加逗号 ,
的意思就是必须是限定的这个位数,有一点不符合规则的都不行
下面说一下?
的匹配规则:
是作用于前面那个东西,可以有可无,有的话只能有一个,要么就不能有!!!!!!
比如在网页上匹配手机号
re.match(r"021-?\d{8}","024-12345678").group()
>>021-12345678
但是如果我要是不加 -
,作用结果就是,同样不会报错,也可以成功的匹配。
#匹配沈阳的手机号
re.match(r"021-?\d{8}","02412345678").group()
>>02112345678
#匹配济南的手机号 #匹配前面是3位或者四位的手机号
re.match(r"\d{3,4}-?\d{8}","0532-12345678").group()
>>0532-12345678
.*
可以匹配任意一个字符,但是不包括换行\n
如果要是有换行的话那么就需要引入一个新的参数,就可以全部的提取到了
html_spyder ="""adasda
sdasd
asd
as
d
asd"""
result =re.match(r".*",html_spyder,re.S).group()
>> adasda
sdasd
asd
as
d
asd
.+
就和 .*
想对应, .+
当是空字符的时候就会报错(至少有一个),但是 .*
永远不会报错(什么都行)
实例分析:
import re
names =["age","_age","1age","age1","a_age","age_1","age!","a#123"]
for name in names:
result = re.match(r"[a-zA-Z0-9_][a-zA-Z0-9_]*",name)
if result:
print("匹配结果为%s匹配出来的结果为%s"%(result,result.group()))
else:
print("匹配失败!")
运行结果:
D:\BaiduNetdiskDownload\python-3.6.6\python.exe G:/python/正则表达式.py
匹配结果为<_sre.SRE_Match object; span=(0, 3), match='age'>匹配出来的结果为age
匹配结果为<_sre.SRE_Match object; span=(0, 4), match='_age'>匹配出来的结果为_age
匹配结果为<_sre.SRE_Match object; span=(0, 4), match='1age'>匹配出来的结果为1age
匹配结果为<_sre.SRE_Match object; span=(0, 4), match='age1'>匹配出来的结果为age1
匹配结果为<_sre.SRE_Match object; span=(0, 5), match='a_age'>匹配出来的结果为a_age
匹配结果为<_sre.SRE_Match object; span=(0, 5), match='age_1'>匹配出来的结果为age_1
匹配结果为<_sre.SRE_Match object; span=(0, 3), match='age'>匹配出来的结果为age
匹配结果为<_sre.SRE_Match object; span=(0, 1), match='a'>匹配出来的结果为a
匹配开头结尾,我们可以发现,age!后面的并没有匹配到,这里我们需要改造一下代码
字符 | 功能 |
---|---|
^ | 匹配字符串开头 |
$ | 匹配字符串结尾 |
import re
names =["age","_age","1age","age1","a_age","age_1","age!","a#123"]
for name in names:
result = re.match(r"^[a-zA-Z0-9_][a-zA-Z0-9_]*[!#]?[0-9]*$",name)
if result:
print("匹配结果为%s匹配出来的结果为%s"%(result,result.group()))
else:
print("匹配失败!")
项目实战: 判断168邮箱是否正确匹配,@符号前面有4到20位,例如hello@168.com
import re
def main():
email =input("请输入邮箱地址:")
#如果在正则表达式中用到了某些普通字符,比如?等,仅仅在他们前面加一个\进行转义
result =re.match("[a-zA-Z0-9]{4,20}@163\.com$",email)
if email:
print("您的邮箱为:%s"%(result))
else:
print("请重新输入!")
if __name__ == '__main__':
main()
匹配分组
字符 | 功能 |
---|---|
| | 匹配左右任意一个表达式 |
(ab) | 将括号中字符作为一个分组 |
\num | 引用分组num匹配到的字符串 |
(?P<name>) | 分组起别名 |
(?P=name) | 引用name分组匹配到的字符串 |
管道 |
尽量不要加,他的意思是或的意思,在管道的前后分为两个部分,前面可以,后面也可以
但是如果我要是想判断多个邮箱的话那么只需要对其进行改造就可
re.match(r"[a-zA-Z0-9_]{4,20}@(163|126)\.COM$","laowang@126.com").group()
>> laowang@126.com
re.match(r"([a-zA-Z0-9_]{4,20})@(163|126)\.COM$","laowang@126.com").group(1)
>> laowang
对于分组,我们主要以网页端<h1>
为例。
html_str ="<h1>rwerwerwer</h1>"
re.match(r"<\w*>.*</\w*>",html_str).group()
我们重新改造一下在第一个分组同样可以成功匹配
html_str ="<h1>rwerwerwer</h1>"
re.match(r"<(\w*)>.*</\1>",html_str).group()
改造(这里一定要注意顺序,千万不要按正常的思考方式来进行思考,倒着思考更好)
html_str ="<h1>rwerwerwer</h1>"
re.match(r"<(\w*)><(\w*)>.*</\2></\1>",html_str).group()
升级,如果我要是想通过分组的方式来进行处理字符串
html_str ="<h1>rwerwerwer</h1>"
re.match(r"<(?P<p1>\w*)><(?P<p2>\w*)>.*</(?P=p2)></(?P=p2)>",html_str).group()
re模块的高级用法(python特有方法):
search
方法:(这个方法于match方法的区别是,它并不是从第一个字符匹配的)如果要是想达到match方法就在匹配方式前面加一个 ^
import re
response =re.search(r"\d+","阅读次数 9999").group()
>>9999
但是它只能匹配到第一个满足要求的字符,后面不会去匹配了
findall
方法: 匹配到规则内所有符合要求的字符
import re
response =re.findall(r"\d+","阅读次数 9999 C++=1123 java =123213").group()
>>['9999','1123','123213']
sub
方法,将匹配到的数据进行替换
import re
response =re.sub(r"\d+","678","阅读次数 9999").group()
>>阅读次数 678
先那正则去匹配,然后将匹配到的数据进行和前面的替换
业务场景:如果想把匹配到最后的结果+1,那么就应该用下面的方式来进行审计
import re
def add(temp):
strnum =temp.group()
num =int(strnum)+1
return str(num)
result =re.sub(r'\d+',add,"python =997")
print(result)
split
方法,根据匹配进行切割字符串,并返回一个列表
需求,切割字符串 info:xiaozhang33shandong
import re
result =re.split(r":|"," info:xiaozhang 33 shandong")
print(result)
import re
text = "123123qweq@qq.com"
reslut=re.match(r"\w+@[0-9a-z]+\.com",text)
print(reslut.group())
import re
text ="https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_9337143847801671495%22%7D&n_type=0&p_from=1"
result =re.match(r"(http|https|ftp)://[^\s]+",text).group()
print(result)
匹配身份证
result =re.match(r"\d{17}[\dXx]",text).group()
print(result)
(ftp|http|https)$
使用 |
时候必须要用括号括起来
贪婪模式和非贪婪模式:
\d+
贪婪模式,默认的回去匹配更多的字符串
\d+?
非贪婪模式,只会去匹配一个
text ="<h1>标题</h1>"
ret =re.match("<.+?>",text)
print(ret.group())
>>标题
如果要是不加问号的话则会全部匹配到 <h1>
案例:匹配0-100之间的数字 09不可以出现 101不可以出现 有三种情况 一位数 两位数 三位数
text ="99"
ret =re.match("[1-9]\d?|100",text)
print(ret.group())
import re
text = "100"
result = re.match("[0-9]\d?$|100$",text).group()
print(result)
import re
text ="apple is price $99 orange is $032"
result =re.match("(.*)(\$\d+)(.*)(\$\d+)",text)
print(result.group(2,4))
拉取拉勾网的信息
import re
text ="""<div class="job-detail">
工作职责:
<br>1、协同完成网站的开发与测试工作;
<br>2、独立完成网站的功能模块编码;
<br>3、参于各项目中的编码工作。
<br>
<br>任职要求:
<br>1、掌握PHP语言,有项目开发经验优先;
<br>2、掌握SQL语句和MySQL数据库;
<br>3、掌握PHP面向对象思想和具有MVC设计思想,良好的代码书写、注释习惯;
<br>4、了解HTML,HTTP等技术;
<br>5、善于学习,有较强的学习能力,工作主动,责任心强,能承受一定工作压力。
</div>"""
result =re.sub('<.+?>',"",text)
print(result)
text = "hello&& word ni hao"
result =re.split('^a-zA-Z',text)
print(result)