开卷有益!如果你正在被正则表达式虐了千百遍依旧待它如初恋,请不要划走,这里或许有你想要的答案!
学无止境!希望往后余生感恩今天的坚持!
活动地址:优快云21天学习挑战赛
终于学习完re模块的re.match()函数,掌握了几种匹配模式的正则表达式写法,感兴趣的同学,欢迎查阅我的正则表达式-学习笔记(1)正则表达式-学习笔记(2),接下来我要紧锣密鼓地学习re模块的其他函数,并争取尽快完成课后练习。坚持!
**
学习日记
**
一、正则表达式学习要点
7、高级用法
①re.search()函数: 扫描整个字符串并返回第一个成功的匹配,匹配成功就返回一个匹配对象,否则返回None。(编号承接上一篇博文,下同)。
re.search(pattern, string, flags=0) : pattern 是用于匹配的正则表达式;string是被匹配的字符串;flags是标志位,用于控制正则表达式匹配的方式,如是否区分大小写(re.I)、多行匹配(re.M)等。
注意:re.match()与re.search()的区别
前者只匹配字符串的开头,如果字符串开头不符合正则表达式,则匹配失败,而返回None,而后者匹配整个字符串,直到找到一个匹配。
>>> import re
>>> line = "Cats are smarter than dogs"
#正则表达式r"(.*) are (.*?) (.+) (?:.*) "表示“子模式1 are 子模式2 子模式3 子模式,re.M|re.I 将标志设置为M和I即进行多行匹配并使匹配对大小写不敏感。
>>> 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))
... print("searchobj.group(3): ", searchobj.group(3))
... print("searchobj.group(4): ",searchobj.group(4)) #第四个圆括号内的分组匹配的内容未被捕获,所以只有前3个分组数据
... else:
... print("Nothing found!")
...
searchobj.group(): Cats are smarter than dogs
searchobj.group(1): Cats
searchobj.group(2): smarter
searchobj.group(3): than
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
IndexError: no such group
注意:该案例中的正则表达式中使用了特殊语法(),圆括号表示捕获分组,会把每个分组里的匹配值保存起来,从左向右以分组的左括号为标志,第一个出现的为组号1,第二个为2,以此类推,例如该案例中的searchobj.group(1)。与()对应的是(?:) ,二者唯一的区别是后者不会将匹配的值保存起来,因而无编号。
②re.findall()函数,在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果有多个匹配模式,则返回元组列表,如果没有找到匹配的则返回空列表。
re.findall(pattern, string, flags=0) : pattern 是用于匹配的正则表达式;string是被匹配的字符串;flags是标志位,用于控制正则表达式匹配的方式,如是否区分大小写(re.I)、多行匹配(re.M)等。
注意:re.match()和re.search()仅匹配一次,而re.findall()是匹配所有
# 统计出python、c、c++相应文章阅读的次数,单个匹配模式,返回列表
>>> import re
#匹配数字,使用"\d+"或者r"\d+"
>>> result = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['9999', '7890', '12345']
>>> result = re.findall("\d+","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['9999', '7890', '12345']
#匹配字母和数字,使用"\w+" 或者r"\w+"
>>> result = re.findall("\w+","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['python', '9999', 'c', '7890', 'c', '12345']
>>> result = re.findall(r"\w+","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['python', '9999', 'c', '7890', 'c', '12345']
#匹配所有字符,\w+.+ 或者\w+.*
>>> result = re.findall(r"\w+.+","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['python = 9999, c = 7890, c++ = 12345']
>>> result = re.findall(r"\w+.*","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['python = 9999, c = 7890, c++ = 12345']
#仅匹配字母、数字和加号,r"\w+\+*"
>>> result = re.findall(r"\w+\+*","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
['python', '9999', 'c', '7890', 'c++', '12345']
#多个匹配模式,返回元组列表
>>> result = re.findall(r"(\w+\+*) = (\d+)","python = 9999, c = 7890, c++ = 12345")
>>> print(result) [('python', '9999'), ('c', '7890'), ('c++', '12345')]
>>> result = re.findall(r"(\w+\+*)=(\d+)","python = 9999, c = 7890, c++ = 12345")
>>> print(result)
[]
注意:正则表达式的书写格式要与被匹配字符串的格式一致,否则会返回空值,比如上面案例中的多模式匹配中,被匹配的字符串python与=间有空格,书写正则表达式时=前后也要有空格。
③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
④re.split(): 根据匹配进行切割字符串,并返回一个列表;
re.split(pattern,string,maxsplit=0,flags=0) : pattern 是匹配的正则表达式;string是被匹配的字符串;maxsplit设置分割次数,默认值是0,表示不限制次数,1表示分割1次;flags为标志位,用于控制正则表达式的匹配方式,如是否区分大小写(I)、多行匹配(M)等。
#re.split()的用法
>>> import re
#以:或空格切割字符串,maxsplit为默认值
>>> result = re.split(r":| ","info:xiaoZahang 33 shandong")
>>> print(result)
['info', 'xiaoZahang', '33', 'shandong']
#maxsplit=1
>>> result = re.split(r":| ","info:xiaoZahang 33 shandong",maxsplit=1)
>>> print(result)
['info', 'xiaoZahang 33 shandong']
#maxsplit=2
>>> result = re.split(r":| ","info:xiaoZahang 33 shandong",maxsplit=2)
>>> print(result)
['info', 'xiaoZahang', '33 shandong']
8、特殊语法
①(?:pattern): ()表示捕获分组,会把每个分组里匹配的值保存起来,从左向右,以分组的左括号为标志,第一个出现的分组的组号为1,第二个为2,以此类推。而(?:)表示非捕获分组,和捕获分组的区别在于不会将匹配的值保存起来。 详见上文re.search案例。
②(?=pattern):正向肯定预查,匹配pattern前面的位置,但不捕获pattern,为非获取匹配。匹配成功即可捕获pattern前面的字符串,匹配失败则报错。
>>> import re
#(?=pattern)表示正向肯定预查
>>> result = re.search("Windows(?=95|98|NT|2000)","Windows2000")
>>> print(result.group())
Windows
>>> result = re.search("Windows(?=95|98|NT|2000)","Windows3.1")
>>> print(result.group())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
③(?!pattern): 正向否定预查,匹配pattern前面的位置,在任何不匹配pattern的字符串开始处匹配查找pattern千的字符串,即匹配失败捕获pattern前的字符串。也是非获取匹配。与(?=pattern)相反。
>>> import re
>>> result = re.search("Windows(?!95|98|NT|2000)","Windows2000")
>>> print(result.group())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
>>> result = re.search("Windows(?!95|98|NT|2000)","Windows3.1")
>>> print(result.group())
Windows
9、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
10、r的作用
python中反斜杠\在正则表达式中为转义符 ,如果你要匹配的字符中包含\,那么使用正则表达式里需要4个"\", 十分容易出错。Python中的原生字符串r''很好的解决这个问题,因为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 "<stdin>", line 1, in <module>
AttributeError: 'NoneType' object has no attribute 'group'
二、实战案例
练习1:从下面的字符串中提取文本
<div>
<p>岗位职责:</p>
<p>完成推荐算法、数据统计、接口、后台等服务器端相关工作</p>
<p><br></p>
<p>必备要求:</p>
<p>良好的自我驱动力和职业素养,工作积极主动、结果导向</p>
<p> <br></p>
<p>技术要求:</p>
<p>1、一年以上 Python 开发经验,掌握面向对象分析和设计,了解设计模式</p>
<p>2、掌握HTTP协议,熟悉MVC、MVVM等概念以及相关WEB开发框架</p>
<p>3、掌握关系数据库开发设计,掌握 SQL,熟练使用 MySQL/PostgreSQL 中的一种<br></p>
<p>4、掌握NoSQL、MQ,熟练使用对应技术解决方案</p>
<p>5、熟悉 Javascript/CSS/HTML5,JQuery、React、Vue.js</p>
<p> <br></p>
<p>加分项:</p>
<p>大数据,数理统计,机器学习,sklearn,高性能,大并发。</p>
</div>
#参考答案:re.sub(r"<[^>]*>| |\n","",test_str)
练习2:提取img标签中的图片链接地址
#字符串
<img data-original="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg" src="https://rpic.douyucdn.cn/appCovers/2016/11/13/1213973_201611131917_small.jpg" style="display: inline;">
#参考答案
re.search(r"https://.*?\.jpg",test_str)
练习3:排除指定字符串
使用^(?!.*abc).*$,其中abc为要排除的字符串
import re
partten = r'^(?!.*abc).*$'
strs = ['abc222', '111abc222', '111abc', 'defg']
for i in strs:
print(re.findall(partten, i))
- ^和$表示从字符串开头开始,匹配到结尾;
- (?!.*)表示排除形如abc的部分;
- 后面的.*表示abc后面还可以有内容