山水沐光 2020-06-05
文章目录
偷学Python第三十一天:Python正则表达式的语法以及re模块的使用
正则表达式的语法
什么是正则表达式
字符类
元字符
正则中的重复
分支条件
贪婪和懒惰
分组
零宽断言
零宽度正预测先行断言
零宽度正回顾后发断言
负向零宽断言
零宽度负预测先行断言
零宽度负回顾后发断言
re模块
正则表达式的装饰符
查找单个匹配项
match
group
search
fullmatch
匹配对象
查找多个匹配项
compile
findall
finditer
分割split
替换
sub
subn
escape
purge
总结
明日学习计划
甜甜有话说
目标:可以用Python做一些简单的数据分析。
坚持完成自己的目标!勿忘初心~
正则表达式的语法
什么是正则表达式
不管是使用Windows的搜索工具,还是在word文档里面的查找和替换,肯定都用过*和?这种通配符,如果想要在某个目录下找到自己写的笔记,小甜最常用的方法就是*.md就可以找到当前文件夹下所有的Markdown文件了;正则表达式可以理解为超复杂的通配符,可以比通配符匹配的更为精准,正规一点的说法就是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。比如密码的限制(8位以上16位以内,不能出现特殊字符等等)、邮箱的格式,距离生活近一点的就是某手上的"你个萌萌",王者荣耀上的"你个**"。这些都是正则表达式的运用。
字符类
但是如果想查到一组限定的字符,比较原音字母(a, e, i, o, u),特殊字符(*, &, %, @)这怎么弄呢?
在正则表达式中使用[]将一组字符包裹起来,就到达了自己的需要,例如原音字符[aeiou],特殊字符[*&%@]即可完美的匹配任意一个
元字符
元字符 说明 正则表达式 与之匹配的字符
. 匹配除换行符以外的任意字符 a1b
a2b
aab
a1b
a2b
aab
…
[^…] 一个反向字符集 a[^a]b abb
a1b
a2b
…
\w 匹配字母、数字或者下划线。等价于 [A-Za-z0-9_] a\wb a1b
a2b
aab
abb
…
\s 匹配任意空白字符 a\sb a b
\d 匹配数字。等价于 [0-9] 1\d3 1任意一个数字3
\b 匹配一个单词边界,也就是指单词和空格间的位置。 \babc\b 可以匹配abc
不能匹配abcd
^ 匹配字符串的开始 用于限定一段内容的开始
$ 匹配字符串的结束 用于限定一段内容的结束
\W 匹配除字母、数字或者下划线。等价于 [^A-Za-z0-9_]
\S 匹配任意非空白字符
\D 非匹配数字。等价于 [^0-9]
\B 匹配非单词边界
如果想要匹配.,?,*这些符号,可以使用转义字符\,比如\.
正则中的重复
语法 说明
{n,m} 重复n到m次
{n,} 重复n或更多次
{n} 重复n次
? 重复0或1次,相当于{0,1}
+ 重复1次或更多次,相当于{1,}
* 重复0次或更多次,相当于{0,}
分支条件
用【|】把不同的规则分隔开
从左到右地测试每个条件,如果满足了某个分枝的话,就不会去再管其它的条件了(就是如果有一个表达式为true,就不会执行后面的表达式,如果一直为false就一直执行)
来一个小栗子:中国地区的手机号样式一般如下
0317-1234567
010-1234567
0317-12345678
010-12345678
(010)1234567
0317 12345678
1
2
3
4
5
6
基本罗列出来了所有的手机号样式,现在假设有一个文本框,里面只能输入这种手机号,如果不符合格式,就会给出提示。
正则表达式
^\(0\d{2,3}\)\d{7,8}$|^0\d{2,3}[-\s]?\d{7,8}$
1
首先这是一个有分支条件的式子,第一个式子依次是表示字符串的开始和结尾^ $,然后是‘\(’转义(,0,数字出现2到3次 转义)数字出现7到8次。第二个式子依次是表示字符串的开始和结尾^ $,然后是0,数字出现2到3次[-\s]{1}是-符号或空格符号出现出现1次,数字出现7到8次
这样在配合编程语法就可以完成这样一个限制输入的内容
贪婪和懒惰
贪婪(尽可能多)
a.*f(abcdefbcedf) → abcdefbcedf
懒惰(尽可能少)
a.*?f(abcdefbcedf) → abcdef
语法 说明
?? 重复0或1次,但尽可能少重复
+? 重复1次或更多次,但尽可能少重复
*? 重复0次或更多次,但尽可能少重复
{n,m}? 重复n到m次,但尽可能少重复
{n,}? 重复n或更多次,但尽可能少重复
{n}? 重复n次,但尽可能少重复
分组
在正则表达式中使用()进行分组,分组之后就可以对某个分组进行操作,比如重复某个分组,对引用某个分组,对某个分组进行命名
语法格式
(?P<name>...)
1
使用小括号进行分组,?P<name>进行命名,如果想在后面进行引用的话使用(?P=name)来进行引用
示例
(\d{1,3}\.){3}\d{1,3}
1
这样就可以完成一个简单的匹配IP地址的表达式
零宽断言
零宽断言就跟它的名字一样,是一种零宽度的匹配,它匹配到的内容不会保存到匹配结果中去,最终匹配结果只是一个位置而已。
作用是给指定位置添加一个限定条件,用来规定此位置之前或者之后的字符必须满足限定条件才能使正则中的字表达式匹配成功。
零宽度正预测先行断言
(?=exp) 零宽度正预测先行断言,自身出现的位置的后面能匹配表达式exp,例如想要匹配以ing结尾的单词显示又不需要ing,这个时候就需要零宽度正预测先行断言;这么说比较抽象,直接上栗子
eating looking singing writing shopping
1
不匹配每个单词的ing
正则表达式
\w+(?=ing)
1
零宽度正回顾后发断言
(?<=exp)零宽度正回顾后发断言,自身出现的位置的前面能匹配表达式exp,就是匹配前面的是某个字符且不匹配他
栗子
匹配re开头的单词不匹配re
此处用到的软件为*RegexBuddy*
负向零宽断言
零宽度负预测先行断言
(?!exp)零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp,简单点说就是后面不能出现某个东东,
我们来查找包含Windows的字符串,但是Windows后面不能是10
这里仅仅查找出来了3个
零宽度负回顾后发断言
(?<!exp) 零宽度负回顾后发断言,来断言此位置的前面不能匹配表达式exp
Python中提供的re模块使Python拥有全部正则表达式的功能
re模块
正则表达式的装饰符
修饰符 描述 完整名称
re.I 使匹配对大小写不敏感 re.IGNORECASE
re.A 让 \w, \W, \b, \B, \d, \D, \s 和 \S 只匹配ASCII,而不是Unicode re.ASCII
re.L 做本地化识别(locale-aware)匹配 re.LOCALE
re.M 多行匹配,影响 ^ 和 $,多行模式下是支持匹配行开头 re.MULTILINE
re.S 使 . 匹配包括换行在内的所有字符 e.DOTALL
re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. re.UNICODE
re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。 re.VERBOSE
查找单个匹配项
match
re.match 如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的匹配对象 。 如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。
语法格式
re.match(pattern, string, flags=0)
1
pattern:匹配的正则表达式
string:要匹配的字符串。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.match方法返回一个匹配的对象,否则返回None。
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string1 = "hello python"
string2 = "hell5o python"
pattern = r"[a-z]+\s\w+" # a-z出现1次到任意次加一个\s加任意字符出现1次到任意次
print(re.match(pattern, string1)) # <re.Match object; span=(0, 12), match=‘hello python‘>
print(re.match(pattern, string2)) # None
1
2
3
4
5
6
7
8
9
10
11
开局导入re模块,r""表示为一个正则表达式
因为string2中间出现了一个数字5 所以不匹配
group
re.group是从Match对象中获取结果的,不过不分组默认为0,分组索引则从0开始(0是完整的一个匹配),如果多个分组,则第一个分组是1;也可以为其命名使用
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string1 = "hello python"
string2 = "hell5o python"
pattern = r"[a-z]+\s\w+"
pattern1 = r"(\w+)(\s)(\w+)"
pattern2 = r"(?P<first>\w+\s)(?P<last>\w+)" # 命名分组
print(re.match(pattern, string1)) # <re.Match object; span=(0, 12), match=‘hello python‘>
print(re.match(pattern, string1).group()) # hello python
print(re.match(pattern, string2)) # None
print(re.match(pattern1, string2).group(0)) # hell5o python
print(re.match(pattern1, string2).group(1)) # hell5o
print(re.match(pattern1, string2).group(2)) # 这里匹配的是那个空格
print(re.match(pattern1, string2).group(3)) # python
print(re.match(pattern2, string2).group("last")) # python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
search
re.search 扫描整个字符串找到匹配样式的第一个位置,并返回一个相应的匹配对象 。如果没有匹配,就返回一个 None ; 注意这和找到一个零长度匹配是不同的。。语法结构和match是一样的
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string = "Hi World Hello python"
pattern = r"Hello python"
print(re.search(pattern, string).group()) # Hello python
print(re.match(pattern, string)) # None
1
2
3
4
5
6
7
8
9
10
两者的区别
re.match 只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而 re.search 匹配整个字符串,直到找到一个匹配。
fullmatch
re.fullmatch如果整个 string 匹配这个正则表达式,就返回一个相应的匹配对象 。 否则就返回 None ; 注意跟零长度匹配是不同的。
语法格式跟上面的也是一样的
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string = "Hi World Hello python"
pattern = r"Hi World Hello python"
pattern1 = r"hi World hello python"
print(re.fullmatch(pattern, string)) # <re.Match object; span=(0, 21), match=‘Hi World Hello python‘>
print(re.fullmatch(pattern1, string)) # None
1
2
3
4
5
6
7
8
9
10
11
12
三者的区别
match:字符串开头匹配
search:查找任意位置的匹配项
fullmatch:整个字符串要与正则表达式完全匹配
匹配对象
匹配对象总是有一个布尔值 True。如果没有匹配的话match() 和 search() 返回 None 所以可以简单的用 if 语句来判断是否匹配
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string = "Hi World Hello python"
pattern = r"Hello python"
match1 = re.search(pattern, string)
match2 = re.match(pattern, string)
if match1:
print(match1.group()) # Hello python
if match2: # 因为match2的值为none所以不执行
print(match2.group())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
查找多个匹配项
compile
re.compile将正则表达式的样式编译为一个正则对象,可以用于匹配
语法结构
re.compile(pattern, flags=0)
1
pattern:匹配的正则表达式
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
findall
re.findall在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。与match 和 search 不同的是 match 和 search 是匹配一次 findall 匹配所有。
语法结构
re.findall(string[, pos[, endpos]])
1
string 待匹配的字符串。
pos 可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度
finditer
pattern 在 string 里所有的非重复匹配,返回为一个迭代器保存了匹配对象 。 string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。
语法结构同match
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
from collections.abc import Iterator # 导入判断是否为迭代器的对象
string = "hello python hi javascript"
pattern = r"\b\w+\b"
pattern_object = re.compile(r"\b\w+\b")
print(type(pattern_object)) # <class ‘re.Pattern‘>
findall = pattern_object.findall(string)
for i in findall:
print(i)
finditer = re.finditer(pattern, string)
# 判断是否为迭代器
print(isinstance(finditer, Iterator)) # True
for _ in range(4):
finditer1 = finditer.__next__() # 取出下一个值
print(finditer1.group())
‘‘‘
--循环结果--
hello
python
hi
javascript
‘‘‘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
如果有超大量的匹配项的话,返回finditer的性能要优于findall,这就是列表和迭代器的区别,在第二十一天的Python中的生成式和生成器有提到
分割split
re.split方法按照能够匹配的子串将字符串分割后返回列表
语法结构
re.split(pattern, string[, maxsplit=0, flags=0])
1
pattern:分隔的正则表达式
string:分隔的文本
maxsplit:分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string = ‘‘‘hello hi good morning
goodnight
python
javascript
Linux
‘‘‘
pattern = r‘\s+‘ # 以空格回车制表符为分隔符
print(re.split(pattern, string)) # 不限制次数分隔
# [‘hello‘, ‘hi‘, ‘good‘, ‘morning‘, ‘goodnight‘, ‘python‘, ‘javascript‘, ‘Linux‘, ‘‘]
print(re.split(pattern, string, 5)) # 分隔5次
# [‘hello‘, ‘hi‘, ‘good‘, ‘morning‘, ‘goodnight‘, ‘python\njavascript\nLinux\n‘]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
与str模块的split不同的是,re模块的split支持正则
替换
sub
re.sub用于替换字符串中的匹配项
语法结构
re.sub(pattern, repl, string, count=0, flags=0)
1
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
到这里就可以完成一个某手的评论区,修改不良评论的小案例
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
string = input("请输入评论:")
pattern = r"[美丽可爱大方]{1}" # 检测的字符
print(re.sub(pattern, "萌", string))
1
2
3
4
5
6
7
8
9
10
效果图
不良评论?不可能的,这辈子都不可能出现的
subn
行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).
escape
re.escape(pattern)转义 pattern 中的特殊字符。例如正则里面的元字符.
示例代码
"""
-*- coding:uft-8 -*-
author: 小甜
time:2020/5/30
"""
import re
pattern = r‘\w\s*\d\d.‘
# 打印pattern的特殊字符
print(re.escape(pattern)) # \\w\\s\*\\d\\d\.
1
2
3
4
5
6
7
8
9
任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的,不过容易出现错误,手动转义比较好
purge
re.purge()清除正则表达式的缓存。
总结
明日学习计划
明天用今天学的知识完成一些案例
甜甜有话说
又是收获满满的一天,很是开心,加油明天会更好
————————————————
原文链接:https://blog.csdn.net/weixin_46163658/article/details/106447424
https://weavi.com/20813801
https://weavi.com/20813795
https://weavi.com/20813794
https://weavi.com/20813792
https://weavi.com/20813786
https://weavi.com/20813782
https://weavi.com/20813781
https://weavi.com/20813780
https://weavi.com/20813776
https://weavi.com/20730018
https://weavi.com/20730008
https://weavi.com/20729997
https://weavi.com/20729985
https://weavi.com/20729957
https://weavi.com/20729968
https://weavi.com/20729943
https://weavi.com/20729928
https://weavi.com/20729909
https://weavi.com/20729844
https://weavi.com/20729854
https://weavi.com/20729788
https://weavi.com/20729731
https://weavi.com/20673472
https://weavi.com/20673459
https://weavi.com/20673434
https://weavi.com/20673417
https://weavi.com/20671935