1.正则表达式的简单介绍
正则表达式是⼀组由字⺟和符号组成的特殊⽂本,它可以⽤来从⽂本中找出满⾜你想要的格式的句⼦。
使用正则表达式确认获得的数据是否是期望值。如:查找字符串中含有的电话号码,email、用户名是否合法等
2.re模块的使用
正则表达式是一种用来描述字符串(文本)特征的语言和工具,被广泛应用于文本处理、数据清洗和信息抽取等方面。Python 提供了内置的 re
模块,用于实现正则表达式的匹配、查找和替换等操作。在 Python 中,使用正则表达式需要先导入re模块。
2.1查找匹配
match与search:查找第一个匹配(相同之处)
re.search接受一个正则表达式和字符串,并返回发现的第一个匹配,可以在任意位置匹配。而re.match接受一个正则表达式,从第一个字符串开始匹配,并返回发现的第一个匹配。如果字符串开始不符合正则表达式,则匹配失败,re.match返回None(不同之处)
import re
rest = re.search(r"[A-Z]","3aB4DE")
print(rest)
result2 = re.match(r"[A-Z]", "3aB4DE")
print(result2)
输出结果为:<re.Match object; span=(2, 3), match='B'> , None
第一个打印结果:B,而第二个未能匹配到。这就是二者的区别
2.2r标志位的作用(raw,即原始字符串)
在 Python 中,反斜杠 \
不仅是正则表达式中的特殊字符,也是字符串中的转义字符。例如,如果我们要匹配一个以反斜杠开头的字符串,在正则表达式中需要用 \\
来表示,但是由于反斜杠在字符串中也是转义字符,因此需要写成 '\\\\'
才能正确表示。
在正则表达式前面加’r’相当于是原生字符串,抑制转义字符的转义,会导致正则表达式接受的值就是被赋值的字面值,也就相当于Python解释器不会进行转换了,赋值r’\\‘,那么正则表达式接受的值就是’\\'。
一般情况下,在使用正则表达式时,不管是否用到转义字符,为了保险起见,只要使用到正则表达式就添加r
2.3match对象 (re.search的实例化对象,match名字可变)
match.group(default=0): 返回匹配的字符串。
group是由正则表达式可以拆分为多个只调用出匹配子集的子组
0是默认参数,表示匹配的整个串,n表示第n个分组
import re
msg = "It's raining cats and dogs"
match = re.search(r"cats", msg)
print(match.group())
输出结果为:cats
match.start():start方法提供了原始字符串中匹配开始的索引
import re
msg = "It's raining cats and dogs"
match = re.search(r"cats", msg)
print(match.start())
输出结果为:13
match.end():end方法提供了原始字符串中匹配开始的索引
import re
msg = "It's raining cats and dogs"
result = re.search(r"cats", msg)
print(result.end())
输出结果为:17
match.groups():groups返回一个包含所有小组字符串的元组,从1到所含的小组号
import re
msg = "It's raining cats and dogs"
result = re.search(r"cats", msg)
print(result.groups())
输出结果为:()
2.4 findall与finditer
findall和finditer: 找到多个匹配项
re.findall: 查找并返回匹配的字符串,返回一个列表
import re
result = re.findall(r"a", "It's raining cats and dogs")
print(result)
输出结果为:['a', 'a', 'a']
re.finditer: 查找并返回匹配的字符串,返回一个迭代器
import re
result = re.finditer(r"a", "It's raining cats and dogs")
print(result)
print(list(result))
输出结果为:<callable_iterator object at 0x000002B089463D90>
[<re.Match object; span=(6, 7), match='a'>, <re.Match object; span=(14, 15), match='a'>, <re.Match object; span=(18, 19), match='a'>]
2.5 正则替换
re.sub(“匹配正则”,"替换内容","string"): 将string中匹配的内容替换为新内容
import re
print( re.sub(r"[A-Z]", "*", "sBEbI"))
输出结果为:s**b*
2.6 正则编译
re.compile("正则表达式")
reg = re.compile(r"[A-Z]")
print(reg.findall("A4bUsadL"))
输出结果为:['A', 'U', 'L']
正则编译的特点:1.复杂的正则可复用。2.使用正则编译更方便,省略了参数。3.re模块缓存它即是编译的正则表达式,因此在大多数情况下,使用complie并没有很大的性能优势
3.基本正则匹配
3.1区间
区间匹配,[] 可以按照编码顺序规定范围,在区间范围内,任意匹配一个,正则匹配区分大小写
下面是代码演示:
import re
result = re.findall(r"Python", "Python 3 python")
print(result)
result = re.findall(r"[Pp]ython", "Python 3 python")
print(result)
输出结果为:['Python'] ['Python', 'python']
3.2区间取反
取反:[^]
ret = re.findall("[^A-Z]c", "acBcc2Ccd")
print(ret)
ret = re.findall("[^A-Z][0-9]", "A2c333dd4")
print(ret)
输出结果为:['ac', 'cc'] ['c3', '33', 'd4']
3.3或匹配
匹配a或b: a|b
msg = "welcome to changsha, welcome to hunan"
ret = re.findall("changsha|hunan", msg)
print(ret)
输出结果为: ['changsha', 'hunan']
3.4 "."占位符
匹配任何(除\n外)的单个字符,它仅仅只出现在方括号字符组以外
ret = re.findall("p.thon","Pythonpyythonppthonp thon p\nthon")
print(ret)
输出结果为:['ppthon', 'p thon']
3.5开始与结束
^接开头,结尾接$
ret = re.findall("^hello", "hello, world, hello")
print(ret)
ret = re.findall("hello$", "hello, world, hello")
print(ret)
ret = re.findall("^hello$", "hello, world, hello")
print(ret)
输出结果为:['hello'] ['hello'] []
3.6快捷方式
3.7 正则重复
* ? + {n} {n,} {n,m} {,m}
# * ? +
# ? 表示匹配前一项0次或1次
ret = re.findall("py?", "python pppy p ps pt")
print(ret)
# + 匹配前一项一次以上 1~n次
ret = re.findall("py+", "python pppyyy p ps pty")
print(ret)
# * 匹配前一项任意次 0~n次
ret = re.findall("py*", "python pppyyy p ps pty")
print(ret)
# {n,m} 匹配前一项n到m次 n-m次
# {n,} 匹配n次以上
# {,m} 匹配0到m次
# {n} 匹配n次
ret = re.findall("py{1,2}", "python pppyyy p ps pty")
print(ret)
输出结果为: ['py', 'p', 'p', 'py', 'p', 'p', 'p']
['py', 'pyyy']
['py', 'p', 'p', 'pyyy', 'p', 'p', 'p']
['py', 'pyy']
4.贪婪模式与非贪婪模式
贪婪模式(.*): 匹配尽可能多的字符-默认模式
非贪婪模式(.*?): 正则\d*?
import re
msg = "<div>test1</div>bb<div>test2</div>"
ret = re.findall(r"<div>.*</div>", msg)
print(ret)
ret = re.findall(r"<div>.*?</div>", msg)
print(ret)
输出结果为:['<div>test1</div>bb<div>test2</div>']
['<div>test1</div>', '<div>test2</div>']
5.正则分组
5.1简单分组
使用括号结合正则表达式
ret = re.search(r"(\d[a-z]){3}", "age325ngas")
print(ret)
ret = re.search(r"(\d{3}[a-z])-(\d{4})", "232lsfw2345t-8888")
print(ret)
print(ret.group(0))
print(ret.group(1))
print(ret.group(2))
输出结果为: <re.Match object; span=(8, 17), match='345t-8888'>
345t-8888
345t
8888
5.2捕获分组
分组之后匹配到的数据都是暂时会放在内存里,并且给定一个从1开始的索引
捕获分组可以使用向后引用
msg = "<div><a href='http://baidu.com'>链接百度</div>"
print( re.search(r"<(\w+)>.*</\1>", msg))
print(re.search(r"(\d[a-z]) (\d[a-z]) \1 \2", "2a 3d 4a 3d"))
输出结果为: <div><a href='http://baidu.com'>链接百度</div>
<re.Match object; span=(0, 11), match='2a 3d 2a 3d'>
5.3非捕获分组
(?: regex), 只分组不捕获, 不会将匹配到的内容临时存放到内存中,不能使用分组向后引用
ret = re.search(r"(?:\d{3})-(\d{4})-\1", "123-2222-2222")
print(ret)
输出结果为:<re.Match object; span=(0, 13), match='123-2222-2222'>
*使用findall去匹配的时候,如果有捕获分组,只会显示捕获分组的内容
ret = re.findall(r"(?:\d{3})-(\d{4})-\1", "123-2222-2222")
print(ret)
输出结果为:['2222']
6.正则标记
re.I 大小写不敏感, re.M 多行匹配, re.S 使用表示换行符在内的任意字符
print(re.findall(r"python", "PYTHOn python", re.I))
msg='''
python
PYthon
'''
print(re.findall(r"^python$", msg, re.I|re.M))
print(re.findall(r".+", msg, re.S))
输出结果为: ['PYTHOn', 'python']
['python', 'PYthon']
['\npython\nPYthon\n']
内联标记:(?imx): 正则表达式包含三种可选标志: i,m 或x, 只影响括号中的区域
(?imx: re): 在括号中使用i,m或x可选标志
7.正则断言(零宽断言)
不占用匹配宽度,只是确定位置
msg = "hellos world, hello sc"
print( re.findall(r"o(?=s)", msg) )
print( re.findall(r"o(?!s)", msg) )
print( re.findall(r"(?<=l)o", msg))
print( re.findall(r"(?<!l)o", msg))
msg = """
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:1e:73:3e brd ff:ff:ff:ff:ff:ff
inet 192.168.1.54/24 brd 192.168.1.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 fe80::20c:29ff:fe1e:733e/64 scope link
valid_lft forever preferred_lft forever
"""
print(re.findall(r"(?<=inet ).*?(?=/2)", msg))
输出结果为: ['o']
['o', 'o']
['o', 'o']
['o']
['192.168.7.54']