100天精通Python(进阶篇)——第34天:正则表达式大总结(基础(1)

最后

🍅 硬核资料:关注即可领取PPT模板、简历模板、行业经典书籍PDF。
🍅 技术互助:技术群大佬指点迷津,你的问题可能不是问题,求资源在群里喊一声。
🍅 面试题库:由技术群里的小伙伴们共同投稿,热乎的大厂面试真题,持续更新中。
🍅 知识体系:含编程语言、算法、大数据生态圈组件(Mysql、Hive、Spark、Flink)、数据仓库、Python、前端等等。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’


**示例3**:`\d`用法



import re

普通的匹配方式

ret = re.match(“嫦娥1号”,“嫦娥1号发射成功”)
print(ret.group())
嫦娥1号

ret = re.match(“嫦娥2号”,“嫦娥2号发射成功”)
print(ret.group())
嫦娥2号

ret = re.match(“嫦娥3号”,“嫦娥3号发射成功”)
print(ret.group())
嫦娥3号

使用\d进行匹配

ret = re.match(“嫦娥\d号”,“嫦娥1号发射成功”)
print(ret.group())
嫦娥1号

ret = re.match(“嫦娥\d号”,“嫦娥2号发射成功”)
print(ret.group())
嫦娥2号

ret = re.match(“嫦娥\d号”,“嫦娥3号发射成功”)
print(ret.group())
嫦娥3号


**其他的匹配符参见后面章节的讲解**


### 3、匹配多个字符


匹配多个字符的相关格式




| 字符 | 功能 |
| --- | --- |
| `*` | 匹配前一个字符出现0次或者无限次,即可有可无 |
| `+` | 匹配前一个字符出现1次或者无限次,即至少有1次 |
| `?` | 匹配前一个字符出现1次或者0次,即要么有1次,要么没有 |
| `{m}` | 匹配前一个字符出现m次 |
| `{m,n}` | 匹配前一个字符出现从m到n次 |


**示例1**:`*`用法


需求:匹配出,一个字符串第一个字母为大小字符,后面都是小写字母并且这些小写字母可有可无



import re

ret = re.match(“[A-Z][a-z]*”,“M”)
print(ret.group())
M

ret = re.match(“[A-Z][a-z]*”,“MnnM”)
print(ret.group())
Mnn

ret = re.match(“[A-Z][a-z]*”,“Aabcdef”)
print(ret.group())
Aabcdef


**示例2**:`+`用法


需求:匹配出,变量名是否有效



import re

names = [“name1”, “_name”, “2_name”, “__name__”]

for name in names:
ret = re.match(“[a-zA-Z_]+[\w]*”,name)
if ret:
print(“变量名 %s 符合要求” % ret.group())
else:
print(“变量名 %s 非法” % name)


输出结果:



变量名 name1 符合要求
变量名 _name 符合要求
变量名 2_name 非法
变量名 name 符合要求


示例3:`?`用法


需求:匹配出,0到99之间的数字



import re

ret = re.match(“[1-9]?[0-9]”,“7”)
print(ret.group())
7

ret = re.match(“[1-9]?\d”,“33”)
print(ret.group())
33

ret = re.match(“[1-9]?\d”,“09”)
print(ret.group())
0 # 这个结果并不是想要的,利用$才能解决


**示例4**:`{m}`用法


需求:匹配出,8到20位的密码,可以是大小写英文字母、数字、下划线



import re

ret = re.match(“[a-zA-Z0-9_]{6}”,“12a3g45678”)
print(ret.group())
12a3g4

ret = re.match(“[a-zA-Z0-9_]{8,20}”,“1ad12f23s34455ff66”)
print(ret.group())
1ad12f23s34455ff66


### 4、匹配开头结尾




| 字符 | 功能 |
| --- | --- |
| `^` | 匹配字符串开头 |
| `$` | 匹配字符串结尾 |


**示例1**: `^`用法


需要:匹配以135开头的电话号码



import re

ret = re.match(“^135[0-9]{8}”,“13588888888”)
print(ret.group())
13588888888

ret = re.match(“^135[0-9]{8}”,“13512345678”)
print(ret.group())
13512345678

136开头的没法匹配就会报错

ret = re.match(“^135[0-9]{8}”,“13688888888”)
print(ret.group())
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’


**示例2**:$


需求:匹配出163的邮箱地址,且@符号之前有4到20位,例如hello@163.com



import re

email_list = [“xiaoWang@163.com”, “xiaoWang@163.comheihei”, “.com.xiaowang@qq.com”]

for email in email_list:
ret = re.match(“[\w]{4,20}@163.com$”, email)
if ret:
print(“%s 是符合规定的邮件地址,匹配后的结果是:%s” % (email, ret.group()))
else:
print(“%s 不符合要求” % email)


输出结果:



xiaoWang@163.com 是符合规定的邮件地址,匹配后的结果是:xiaoWang@163.com
xiaoWang@163.comheihei 不符合要求
.com.xiaowang@qq.com 不符合要求


### 5、匹配分组




| 字符 | 功能 |
| --- | --- |
| ` | ` |
| `(ab)` | 将括号中字符作为一个分组 |
| `\num` | 引用分组num匹配到的字符串 |
| `(?P<name>)` | 分组起别名 |
| `(?P=name)` | 引用别名为name分组匹配到的字符串 |


**示例1**:`|`用法


需求:匹配出0-100之间的数字



import re

ret = re.match(“[1-9]?\d”,“8”)
print(ret.group())
8

ret = re.match(“[1-9]?\d”,“78”)
print(ret.group())
78

不正确的情况

ret = re.match(“[1-9]?\d”,“08”)
print(ret.group())
0

修正之后的

ret = re.match(“[1-9]?\d$”,“08”)
if ret:
… print(ret.group())
… else:
… print(“不在0-100之间”)

不在0-100之间

添加|

ret = re.match(“[1-9]?\d$|100”,“8”)
print(ret.group()) # 8
8

ret = re.match(“[1-9]?\d$|100”,“78”)
print(ret.group()) # 78
78

ret = re.match(“[1-9]?\d$|100”,“08”)

print(ret.group()) # 不是0-100之间

ret = re.match(“[1-9]?\d$|100”,“100”)
print(ret.group()) # 100
100


**示例2**:`()`用法


需求:匹配出163、126、qq邮箱



import re

ret = re.match(“\w{4,20}@163.com”, “test@163.com”)
print(ret.group())
test@163.com

ret = re.match(“\w{4,20}@(163|126|qq).com”, “test@126.com”)
print(ret.group())
test@126.com

ret = re.match(“\w{4,20}@(163|126|qq).com”, “test@qq.com”)
print(ret.group())
test@qq.com

ret = re.match(“\w{4,20}@(163|126|qq).com”, “test@gmail.com”)
if ret:
… print(ret.group())
… else:
… print(“不是163、126、qq邮箱”)

不是163、126、qq邮箱


需求:不是以4、7结尾的手机号码(11位)



import re

tels = [“13100001234”, “18912344321”, “10086”, “18800007777”]

for tel in tels:
ret = re.match(“1\d{9}[0-35-68-9]”, tel)
if ret:
print(ret.group())
else:
print(“%s 不是想要的手机号” % tel)


输出结果:



18912344321
10086 不是想要的手机号
18800007777 不是想要的手机号


需求:提取区号和电话号码



import re

ret = re.match(“([^-]*)-(\d+)”,“010-12345678”)
print(ret.group())
010-12345678

print(ret.group(1))
010

print(ret.group(2))
12345678


**示例3**:`\`用法


需求:匹配出`<html>hh</html>`



import re

能够完成对正确的字符串的匹配

ret = re.match(“<[a-zA-Z]*>\w*</[a-zA-Z]*>”, “hh”)
print(ret.group())

hh

如果遇到非正常的html格式字符串,匹配出错

ret = re.match(“<[a-zA-Z]*>\w*</[a-zA-Z]*>”, “hh”)
print(ret.group())

hh

正确的理解思路:如果在第一对<>中是什么,按理说在后面的那对<>中就应该是什么

通过引用分组中匹配到的数据即可,但是要注意是元字符串,即类似 r""这种格式

ret = re.match(r"<([a-zA-Z]*)>\w*</\1>", “hh”)
print(ret.group())

hh

因为2对<>中的数据不一致,所以没有匹配出来

test_label = “hh”
ret = re.match(r"<([a-zA-Z]*)>\w*</\1>“, test_label)
if ret:
… print(ret.group())
… else:
… print(”%s 这是一对不正确的标签" % test_label)

hh 这是一对不正确的标签

**示例4:**`\number`用法


需求:匹配出`<html><h1>www.itcast.cn</h1></html>`



import re

labels = [“

www.itcast.cn

”, “

www.itcast.cn

”]

for label in labels:
ret = re.match(r"<(\w*)><(\w*)>.*</\2></\1>“, label)
if ret:
print(”%s 是符合要求的标签" % ret.group())
else:
print(“%s 不符合要求” % label)


输出结果:



www.itcast.cn

是符合要求的标签

www.itcast.cn

不符合要求

**示例5**:`(?P<name>) (?P=name)`用法


需求:匹配出`<html><h1>www.itcast.cn</h1></html>`



import re

ret = re.match(r"<(?P\w*)><(?P\w*)>.*</(?P=name2)></(?P=name1)>", “

www.itcast.cn

”)
print(ret.group())

www.itcast.cn

ret = re.match(r"<(?P\w*)><(?P\w*)>.*</(?P=name2)></(?P=name1)>", “

www.itcast.cn

”)
print(ret.group())
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’


**注意**:`(?P<name>)和(?P=name)`中的字母p大写  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/d5f16645d93f4a6a8db229b769489242.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP6KKBSVRTdXBlcg==,size_20,color_FFFFFF,t_70,g_se,x_16)


### 6、高级用法


#### re.search



> 
> re.search 扫描整个字符串并返回第一个成功的匹配;匹配成功re.search方法返回一个匹配的对象,否则返回None。
> 
> 
> 


**函数语法**:`re.search(pattern, string, flags=0)`


**参数说明**:


* `pattern`: 匹配的正则表达式
* `string`: 要匹配的字符串。
* `flags`: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。


案例:



import re

line = “Cats are smarter than dogs”

searchObj = re.search( r’(.*) are (.*?) .*', line, re.M|re.I)

if searchObj:
print ("searchObj.group() : ", searchObj.group())
print ("searchObj.group(1) : ", searchObj.group(1))
print ("searchObj.group(2) : ", searchObj.group(2))
else:
print (“Nothing found!!”)


输出结果:



searchObj.group() : Cats are smarter than dogs
searchObj.group(1) : Cats
searchObj.group(2) : smarter


**re.match与re.search的区别**



> 
> re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
> 
> 
> 



import re

line = “Cats are smarter than dogs”

matchObj = re.match( r’dogs’, line, re.M|re.I)
if matchObj:
print ("match --> matchObj.group() : ", matchObj.group())
else:
print (“No match!!”)

matchObj = re.search( r’dogs’, line, re.M|re.I)
if matchObj:
print ("search --> matchObj.group() : ", matchObj.group())
else:
print (“No match!!”)


输出结果:



No match!!
search --> matchObj.group() : dogs


#### re.findall



> 
> 在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的,则返回空列表。
> 
> 
> 


**注意**: match 和 search 是匹配一次 findall 匹配所有。


**函数语法**:`re.findall(pattern, string, flags=0)`


**参数说明**:


* `pattern`: 匹配的正则表达式
* `string`: 要匹配的字符串。
* `flags`: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。


**案例**:统计出python、c、c++相应文章阅读的次数



import re

ret = re.findall(r"\d+", “python = 9999, c = 7890, c++ = 12345”)
print(ret)
[‘9999’, ‘7890’, ‘12345’]


**案例**:多个匹配模式,返回元组列表



import re

result = re.findall(r’(\w+)=(\d+)', ‘set width=20 and height=10’)
print(result)
[(‘width’, ‘20’), (‘height’, ‘10’)]


#### re.sub



> 
> 将匹配到的数据进行替换
> 
> 
> 


**函数语法**:`re.sub(pattern, repl, string, count=0, flags=0)`


**参数说明**(前三个为必选参数,后两个为可选参数。):


* `pattern` : 正则中的模式字符串。
* `repl` : 替换的字符串,也可为一个函数。
* `string` : 要被查找替换的原始字符串。
* `count` : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
* `flags` : 编译时用的匹配模式,数字形式。


案例:



import re

phone = “2004-959-559 # 这是一个电话号码”

删除注释

num = re.sub(r’#.*$', “”, phone)
print ("电话号码 : ", num)
电话号码 : 2004-959-559

移除非数字的内容

num = re.sub(r’\D’, “”, phone)
print ("电话号码 : ", num)
电话号码 : 2004959559


**repl 参数是一个函数**


**案例**:将字符串中的匹配的数字乘于 2



import re

将匹配的数字乘于 2

def double(matched):
value = int(matched.group(‘value’))
return str(value * 2)

s = ‘A23G4HFD567’
print(re.sub(‘(?P\d+)’, double, s))


输出结果:



A46G8HFD1134


#### re.split



> 
> 根据匹配进行切割字符串,并返回一个列表
> 
> 
> 


**函数语法**:`re.split(pattern, string[, maxsplit=0, flags=0])`


**参数说明**:


* `pattern`: 匹配的正则表达式
* `string`: 要匹配的字符串。
* `maxsplit`:分割次数,maxsplit=1 分割一次,默认为 0,不限制次数。
* `flags`: 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。


**案例**:以`:`或者`空格`切割字符串“info:xiaoZhang 33 shandong”



import re

ret = re.split(r"😐 ",“info:xiaoZhang 33 shandong”)
print(ret)
[‘info’, ‘xiaoZhang’, ‘33’, ‘shandong’]


**案例**:对于一个找不到匹配的字符串而言,split 不会对其作出分割



import re

re.split(‘a’, ‘hello world’)
[‘hello world’]


### 7、特殊语法讲解


#### (?:pattern)



> 
> `()`表示捕获分组,`()`会把每个分组里的匹配的值保存起来,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。而`(?:)`表示非捕获分组,和捕获分组唯一的区别在于,非捕获分组匹配的值不会保存起来。
> 
> 
> 



import re

a = “123abc456”

捕获所有分组

ret = re.search(“([0-9]*)([a-z]*)([0-9]*)”,a)
print(ret.group(1))
123
print(ret.group(2))
abc
print(ret.group(3))
456

仅捕获后两个分组

ret = re.search(“(?:[0-9]*)([a-z]*)([0-9]*)”,a)
print(ret.group(1))
abc
print(ret.group(2))
456
print(ret.group(3)) # 因为第一个括号中的分组并未捕获所有只有两个分组数据
Traceback (most recent call last):
File “”, line 1, in
IndexError: no such group


**说明**:`(?:pattern)`匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。


#### (?=pattern)



> 
> 正向肯定预查(look ahead positive assert),匹配pattern前面的位置。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
> 
> 
> 



import re

ret = re.search(“Windows(?=95|98|NT|2000)”,“Windows2000”)
print(ret.group())
Windows

ret = re.search(“Windows(?=95|98|NT|2000)”,“Windows3.1”)
print(ret.group())
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’


**说明**:`"Windows(?=95|98|NT|2000)"`能匹配`"Windows2000"`中的 Windows,但不能匹配`"Windows3.1"`中的 Windows。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。


`(?:pattern)`和`(?=pattern)`的区别:


* (?:pattern) 匹配得到的结果包含pattern,(?=pattern) 则不包含。如:

 

import re

(?:pattern)

ret = re.search(“industr(?:y|ies)”,“industry abc”)
print(ret.group())
industry

(?=pattern)

ret = re.search(“industr(?=y|ies)”,“industry abc”)
print(ret.group())
industr

* (?:pattern) 消耗字符,下一字符匹配会从已匹配后的位置开始。(?=pattern) 不消耗字符,下一字符匹配会从预查之前的位置开始,如:  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/c616496c470048ae9fb2f8b5aeb8988e.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5bCP6KKBSVRTdXBlcg==,size_20,color_FFFFFF,t_70,g_se,x_16)


#### (?!pattern)



> 
> 正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。
> 
> 
> 



import re

ret = re.search(“Windows(?!95|98|NT|2000)”,“Windows2000”)
print(ret.group())
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’

ret = re.search(“Windows(?!95|98|NT|2000)”,“Windows3.1”)
print(ret.group())
Windows


**说明**:`"Windows(?=95|98|NT|2000)"`不能匹配`"Windows2000"`中的 Windows,但能匹配`"Windows3.1"`中的 Windows。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。与(?=pattern)相反


### 8、python贪婪和非贪婪



> 
> 正则表达式模式中使用到通配字,那它在从左到右的顺序求值时,会尽量“抓取”满足匹配最长字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪则相反,总是尝试匹配尽可能少的字符。在`"*","?","+","{m,n}"`后面加上`?`,使贪婪变成非贪婪。
> 
> 
> 



import re

str = ‘www.baidu.com/path’

‘+’贪婪模式,匹配1个或多个

ret = re.match(r’\w+', str)
print(ret.group())
www

‘+?’非贪婪模式,匹配1个

ret = re.match(r’\w+?', str)
print(ret.group())
w

{2,5}贪婪模式最少匹配2个,最多匹配5个

ret = re.match(r’\w{2,5}', str)
print(ret.group())
www

{2,5}?非贪婪模式,匹配两个

ret = re.match(r’\w{2,5}?', str)
print(ret.group())
ww


### 9、r的作用



> 
> 与大多数编程语言相同,正则表达式里使用`"\"`作为转义字符,这就可能造成反斜杠困扰。假如你需要匹配文本中的字符`"\"`,那么使用编程语言表示的正则表达式里将需要`4个反斜杠"\\"`:前两个和后两个分别用于在编程语言里转义成反斜杠,转换成两个反斜杠后再在正则表达式里转义成一个反斜杠。
> 
> 
> 



> 
> Python里的原生字符串`r'`很好地解决了这个问题,有了原生字符串,你再也不用担心是不是漏写了反斜杠,写出来的表达式也更直观。
> 
> 
> 



import re
mm = “c:\a\b\c”
mm
‘c:\a\b\c’

print(mm)
c:\a\b\c
re.match(“c:\\”,mm).group()
‘c:\’

ret = re.match(“c:\\”,mm).group()
print(ret)
c:\

ret = re.match(“c:\\a”,mm).group()
print(ret)
c:\a

ret = re.match(r"c:\a",mm).group()
print(ret)
c:\a

ret = re.match(r"c:\a",mm).group()
Traceback (most recent call last):
File “”, line 1, in
AttributeError: ‘NoneType’ object has no attribute ‘group’

在这里插入图片描述

感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的:

① 2000多本Python电子书(主流和经典的书籍应该都有了)

② Python标准库资料(最全中文版)

③ 项目源码(四五十个有趣且经典的练手项目及源码)

④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)

⑤ Python学习路线图(告别不入流的学习)

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 7
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值