python正则表达式
爬虫学习记录
下面会用到到网站https://regex101.com/
正则表达式的函数
python提供了一个re
模块这个模块提供了很多的方法和函数
match()函数
使用方法
他的格式,他有三参数,这个函数会从起始位置进行匹配如果匹配失败就返回none
1 | re.match(匹配的正则表达式, 要匹配的字符串, 可选参数标志位控制匹配的比如是否区分大小写等) |
正则表达式修饰符 - 可选标志
修饰符 描述 re.I 使匹配对大小写不敏感 re.L 做本地化识别(locale-aware)匹配 re.M 多行匹配,影响 ^ 和 $ re.S 使 . 匹配包括换行在内的所有字符 re.U 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. re.X 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解。
实测
匹配错误返回
代码
1 | import re |
结果:返回一个None
匹配正确返回
代码
1 | import re |
结果:匹配正确,返回一个对象
方法
他进行是返回一个对象那么我们就可以用里面的方法了
查看里面的方法可以用dir
函数
可以看见有很多的方法
下面我列出几个常用的方法
常用的方法 | 描述 |
---|---|
group() | 返回匹配的字符串 |
span() | 返回匹配的范围 |
start() | 返回从那开始匹配的 |
groups() | 返回全部分组 |
group()选择返回的字符串
实测
1
2
3
4
5
6
7
8
9
10import re
a="abc"
b="abc def ghi"
# a和b进行匹配
c=re.match(a,b)
# 输出匹配的字符串
print(c.group())结果
1
abc
span()返回匹配的范围
1
2
3
4
5
6
7
8
9import re
a="abc"
b="abc def ghi"
# a和b进行匹配
c=re.match(a,b)
# 输出匹配的范围
print(c.span())结果
1
(0, 3)
start()返回从那开始匹配的
1
2
3
4
5
6
7
8
9import re
a="abc"
b="abc def ghi"
# a和b进行匹配
c=re.match(a,b)
# 输出从那开始匹配的
print(c.start())结果
1
0
第三个可选参数标志位
比如代码是下面这样的
1 | import re |
结果,应为他是AB和ab是不匹配的
1 | None |
我们就可以用到参数标志位,不区分大小写
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 3), match='abc'> |
字符的使用
字符 | 描述 |
---|---|
. | 匹配任意一个字符(除了\n) |
[] | 匹配列表中的内容(点就是点而不是如何字符) |
\w | 匹配字母、数字及下划线比如a-z,A-Z,_ |
\W | 匹配不是字母、数字及下划线的字符 |
\s | 匹配任意空白字符,等价于 [\\t\\n\\r\\f] |
\S | 匹配任意非空字符 |
\d | 匹配任意数字,等价于 [0-9] |
\D | 匹配任意非数字的字符 |
\Z | 匹配字符串结尾,如果有换行会往下匹配 |
\A | 匹配字符串开头 |
^ | 匹配一行字符串的开头 |
$ | 匹配一行字符串的结尾 |
\n | 匹配一个换行符 |
\t | 匹配一个制表符 |
* | 匹配 0 个或多个表达式 |
+ | 匹配 1 个或多个表达式 |
? | 匹配 0 个或 1 个前面的正则表达式定义的片段(非贪婪方式) |
{n} | 精确匹配 n 个前面的表达式 |
a|b | 匹配 a 或 b |
( ) | 匹配括号内的表达式,也表示一个组 |
\ | 转义符 |
全部的实测
.
匹配任意一个字符
这个点.
就相当于如何字符
1 | import re |
结果
1 | <re.Match object; span=(0, 1), match='a'> |
[]
匹配列表中的内容
这个[]
匹配列表中的内容,比如[15]
就是只匹配1
和5
,要是[1-5]
就是只匹配1
到5
,如果是[a-z]
就是匹配到a到z
可以看到他只匹配1
到5
代码测试
1 | import re |
结果:匹配1到5到的数字4也是这个范围的
1 | <re.Match object; span=(0, 1), match='4'> |
\w
匹配匹配字母数字下划线
演示可以看见数字和字母都可以匹配到
代码测试
1 | import re |
结果
1 | <re.Match object; span=(0, 2), match='a1'> |
\W
匹配不是字母数字下划线
可以看见下面字符都是可以匹配的,他是和小写的\w
是对立的
\s
匹配任意空白字符
\s
匹配任意空白字符匹配任意空白字符,等价于 [\\t\\n\\r\\f]
\S
匹配任意非空字符
这个只要不是空就匹配上和小写的\s
是对立的
\d
匹配任意数字
\d
匹配任意数字,等价于 [0-9]
\D
匹配任意非数字的字符
他是和小写的\d
是对立的
\Z
匹配字符串结尾
这个\Z
是和$
有差别的
\Z
匹配字符串结尾,如果他匹配到换行符也会跟着换行符往下匹配$
只会匹配到换行符前的
\A
匹配字符串开头
这个\A
和^
差不多
^
是匹配一行字符串的开头\A
匹配字符串开头
代码测试
1 | # -*- coding: utf-8 -*- |
结果
1 | <re.Match object; span=(0, 3), match='aaa'> |
^
匹配一行字符串的开头
这个\A
和^
差不多
^
是匹配一行字符串的开头\A
匹配多行字符串开头
$
匹配一行字符串的结尾
他和^是对立的
这个\Z
是和$
有差别的
\Z
匹配字符串结尾,如果他匹配到换行符也会跟着换行符往下匹配$
只会匹配到换行符前的
\n
匹配换行符
代码演示
1 | import re |
结果
1 | 蔡徐坤 135000000 |
\t
匹配制表符
这个演示不了
*
匹配0个或多个
他*
和+
差不多
*
匹配0个或n个 ,如果一个没有匹配到也不会返回None+
匹配1个或n个,如果一个都没有匹配到他就会返还None
代码
1 | import re |
结果:可以看见他就匹配一个a
1 | a |
如果我添加一个*那就可以叫后面的a都匹配上
1 | import re |
结果:可以看见后面的a都匹配上了
1 | aaaaaaa |
如果我有个不匹配也不会返回None
代码
1 | import re |
结果:他结果并没有返回None
1 | <re.Match object; span=(0, 0), match=''> |
+
匹配1个或多个
他*
和+
差不多
*
匹配0个或n个 ,如果一个没有匹配到也不会返回None+
匹配1个或n个,如果一个都没有匹配到他就会返还None
代码
1 | import re |
结果:可以看见他就匹配一个a
1 | a |
如果我添加一个*那就可以叫后面的a都匹配上
1 | import re |
结果:可以看见后面的a都匹配上了
1 | aaaaaaa |
如果我有个不匹配就会返还None
代码
1 | import re |
结果
1 | None |
?
匹配 0 个或 1 个
在一个?
他不是贪婪模式,他是前面的正则表达式定义的片段
?他是匹配 0 个或 1 个,如果匹配不到也不会返回None
代码
1 | import re |
结果:返回他匹配到的
1 | <re.Match object; span=(0, 1), match='a'> |
我让他匹配一个没有的他也不会返回None
代码
1 | import re |
代码
1 | <re.Match object; span=(0, 1), match=''> |
如果我不添加?
程序就返回None
代码
1 | import re |
结果
1 | None |
{n}
匹配自己指定次数
测试指定指定次数
指定匹配多少
1
2
3
4
5
6
7
8import re
pattern='12121212bcdef'
# 匹配3个数字
x =re.match('\d{3}',pattern)
print(x)结果:可以看见他匹配了三个
1
<re.Match object; span=(0, 3), match='121'>
指定匹配范围
代码
1
2
3
4
5
6
7
8import re
pattern='12121212bcdef'
# 匹配2-5个数字
x =re.match('\d{2,5}',pattern)
print(x)结果:应为他都是按照最多进行匹配所以会匹配到2个
1
<re.Match object; span=(0, 5), match='12121'>
匹配最少多几个
1
2
3
4
5
6
7
8import re
pattern='12121212bcdef'
# 匹配最少2个数字,最多不限制
x =re.match('\d{2,}',pattern)
print(x)结果:应该
,
后面不添加就是无限1
<re.Match object; span=(0, 8), match='12121212'>
a|b
匹配 a
或 b
比如我们想执行匹配w和m那就可以用到|
符号了
1 | import re |
结果
1 | <re.Match object; span=(0, 1), match='w'> |
( )
分组
学习网址https://www.bilibili.com/video/BV1N64y1u7Ty?p=10
基本分组
什么是分组,比如我们匹配一个字符串他只能匹配输出一组,我们可以用()
进行分组
演示
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 15), match='zhao:2737977997'> |
比如我们想叫zhao
和2737977997
进行分开我们就可以用()
进行分组
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 15), match='zhao:2737977997'> |
我们还可以选择要选择输出的分组用group()
咧group(1)
或者groups()[1]
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 15), match='zhao:2737977997'> |
分组引用
比如我们想匹配一个HTML
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 28), match='<bead>匹配</bead>'> |
上面的代码如果我匹配不同的比如<bead>匹配</h1>
上面的代码他也会被匹配到
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 13), match='<bead>匹配</h1>'> |
如果我们只匹配对应的HTML比如<bead></bead>
这样对应如果不对应就不匹配我们就可以用分组引用
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 15), match='<bead>匹配</bead>'> |
如果我改成
1 | import re |
结果
1 | None |
引用起别名
起别名格式(?p<起的名字>表达式)
引用(?p=引用的分组名字)
代码
1 | import re |
结果
1 | <re.Match object; span=(0, 15), match='<bead>匹配</bead>'> |
如果我匹配到不一样比如<bead>匹配</h1>
代码
1 | import re |
结果
1 | None |
\
转义符
比如我们想输入\n
这个,在代码里面不能直接输入\n
要通过\
来转义了
在python里面可以在前面添加上一个r
防止字符转义的,可以省略\
转义符下面有演示
看一下我直接用\n
\n
转义符代码
1
print('\nabc')
结果:可以看见他是回车
1
2
abc我们就可以用
\
来转义代码
1
print('\\nabc')
结果:可以看见这样就可以了
1
\nabc
r
预防转义Python也可以用
r
预防转义代码
1
print(r'\nabc')
结果:前面添加一个
r
就可以预防转义了1
\nabc
在正则表达式里面又如果匹配字符串里面的正则字符那
正则符号匹配
1
2
3
4
5
6
7
8import re
pattern='*das'
# 在正则里面*是匹配0次或多次,
x =re.match('*',pattern)
print(x)结果:就报错了,应为在正则里面*是匹配0次或多次的意思
1
2
3
4
5File "/usr/lib/python3.9/sre_parse.py", line 443, in _parse_sub
itemsappend(_parse(source, state, verbose, nested + 1,
File "/usr/lib/python3.9/sre_parse.py", line 668, in _parse
raise source.error("nothing to repeat",
re.error: nothing to repeat at position 0就可以用\进行转义
代码
1
2
3
4
5
6
7
8import re
pattern='*das'
# 在正则里面*是匹配0次或多次,我们用\进行转义
x =re.match('\*',pattern)
print(x)结果:就可以匹配出来了
1
<re.Match object; span=(0, 1), match='*'>
特殊字符串匹配
特殊字符就是
\n
了\t
了等1
2
3
4
5
6
7import re
pattern='\\t'
x =re.match('\\t',pattern)
print(x)结果:下面的结果为什么是None这是应为在,正则里面\也是转义符
1
None
我们需要添加双倍的
\\
进行转义代码
1
2
3
4
5
6
7import re
pattern='\\t'
# 就是\转义\
x =re.match('\\\\t',pattern)
print(x)结果
1
<re.Match object; span=(0, 2), match='\\t'>
也可以在匹配到添加
r
预防转义代码
1
2
3
4
5
6
7import re
pattern='\\t'
# 防止字符转义
x =re.match(r'\\t',pattern)
print(x)结果
1
<re.Match object; span=(0, 2), match='\\t'>
?非贪婪模式
在下面
search()函数
search()函数,在匹配时会扫描整个字符串,然后返回第一个成功匹配的结果,如果搜索完了还没有找到,就返回 None
格式
1 | re.search(pattern, string, flags=0) |
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串。 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。 |
match()测试
1 | import re |
结果:应为match()函数只能从开头匹配第一个不是H而是E,所以直接就返回了None
1 | None |
我们就可以用search()函数来匹配了
1 | import re |
结果:可以看见成功,应为在匹配时会扫描整个字符串
1 | <re.Match object; span=(13, 18), match='Hello'> |
findall()和finditer()函数
findall()函数
findall()他会获得表达式里面的全部内容,返回形式为数组
他的语法
1 | re.findall(pattern, string, flags=0) |
字符 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配到字符串 |
flags | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解如 re.IGNORECASE 等 |
代码
1 | import re |
结果:他和这个https://regex101.com/r/Ljaf9U/1差不多的他会返回表达式所匹配的全部内容
1 | ['13500000001'] |
finditer()函数
findall()和finditer()函数是一样的,就是finditer()函数他返回的是迭代器,什么是迭代器可以看我这个笔记https://www.zssnp.top/2021/06/09/pythonddq/
1 | import re |
结果
1 | <callable_iterator object at 0x7faec31272b0> |
我们可以通过for进行迭代输出结果
1 | import re |
结果
1 | <re.Match object; span=(4, 5), match='1'> |
sub()和subn()函数
sub()这个函数是替换用的,可以叫文本的指定的字符替换掉
他俩的区别就是
- sub():他返回替换后的结果
- subn():他返回的是一个元组
sub()
代码
1 | import re |
结果
1 | aKyroiRixLg |
subn()
1 | import re |
结果
1 | ('aKyroiRixLg', 6) |
compile()函数
compile()函数将指定的源作为代码对象返回,并准备执行,他里面也是包含sub(),findall(),search(),match()
等方法
下面代码演示一下
1 | import re |
结果
贪婪模式和非贪婪模式
正则表达式默认就是贪婪模式
贪婪模式就是尽可能的匹配多的
非贪婪模式尽可能匹配少的
看一下什么是贪婪模式,他匹配的是|<|h1>>>>>>|>|
最外面的
看一下什么是非贪婪模式,他匹配的是|<|h1|>|>>>>>>
最少的