究竟什么是“正则表达式”?
相信好多小伙伴都听说过“正则表达式”的名号。可我是一直都不太明白什么是正则表达式。直到上午,我看了好几个讲解b站将正则表达式的文章,才有了大梦方醒的感觉。我用我的方式来梳理下正则表达式。
目录
究竟什么是“正则表达式”? | |
---|---|
定义 | |
为什么要学习正则表达式? | |
主要函数 | |
符号表 | |
贪婪模式与非贪婪模式 | |
语法 | |
小节 | |
结语 |
定义
完事开头难,我们首先要对正则表达式有一个初步的理解和解释,明白它是什么,是干什么玩意的?
这是百度百科中的解释,我们可以注意到其中的关键词:
逻辑公式 文本模式
按我的理解就是,正则表达式是为了过滤与匹配而诞生的,而正则表达式就是我要进行匹配的所用的模子。
我的信息就是一堆圆和方块,我的模具是圆,那通过函数我就能将圆的内容匹配出来。
为什么要学习正则表达式?
那么学习了正则表达式,我们能做些什么呢?
1.信息筛选
可以快速检索你的文件中是否包含你想看到的信息,会出现多少次?进而方便你做决策是否看这个文件。
2.过滤
在网络爬虫操作中,我们得到的网页前端信息里面包含很多对我们没有用的内容,我们要通过适当地方式将它们一一过滤掉。
主要函数
正则表达式的函数属于第三方库re库,要使用时需要在代码开始时进行导入。
(注: 下面内容re(正则表达式)看不懂没关系,只要知道re是用于匹配的模板就好)
import re
其主要函数有以下几个:
re.search(re,string) 在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
re.match(re,string) 从一个字符串的开始位置起匹配正则表达式,返回match对象
re.findall(re,string) 搜索字符串,以列表类型返回全部能匹配的子串
re.split(re,string) 将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
re.finditer(re,string) 搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象
re.sub(re,str,string) 在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串
(上述函数中re为正则表达式,string为想要处理的字符串。)
此处摘自:
注意:print(match对象)并不会直接输出匹配内容,而会输出:

import re
text='To be or not to be'
a=re.match(r'.',text)
print(a)
<re.Match object; span=(0, 1), match=‘T’>
match对象会给出字节位置和内容等信息。
如果我们想要只得到匹配内容,就只要输出match对象的group()函数即可:
import re
text='To be or not to be'
a=re.match(r'.',text).group()
print(a)
T
下面我分开来讲解各个函数的用法及作用:
re.search(re,string)
搜索到第一个要检索的对象,并且返回对应的match对象。
import re
text='To be or not to be'
print(re.search(r'be',text))
print(re.search(r'be',text).group())
<re.Match object; span=(3, 5), match=‘be’>
be
可以看到,尽管text中有两个be,但是最后只会返回一个be,对应字节位置为3和4,返回的span就是(3,5),类似的To的span就是(0,2)。
re.match(re,string)
从字符串的开始位置起匹配正则表达式,返回match对象。
import re
text='To be or not to be'
print(re.match(r'To',text))
print(re.match(r'To',text).group())
print(re.match(r'be',text))
print(re.match(r'be',text).group())
<re.Match object; span=(0, 2), match=‘To’>
To
None
AttributeError: ‘NoneType’ object has no attribute ‘group’
可以看到,match匹配到的对象必须是在字符串的开头,如果是在后面出现则会匹配不到而返回None。
对于None大家可以去下面这个博客了解下:
None对象没有group()属性,所以第4个print会输出错误。
re.findall(re,string)
搜索字符串,以列表类型返回全部能匹配的子串:
import re
text='To be or not to be'
print(re.findall(r'be',text))
[‘be’, ‘be’]
我们把findall()函数和search()函数对比学习:
1.返回不同:findall()函数的返回值是列表属性,而search()函数的返回值是match属性
2.效果不同:findall()函数会返回全部匹配的字符串,而search()函数只会返回第一个匹配的字符串。
re.split(re,string)
将一个字符串按照正则表达式匹配结果进行分割,返回列表类型
import re
text='To be or not to be'
print(re.split(r'be',text))
print(re.split(r'(be)',text))
['To ', ’ or not to ', ‘’]
['To ', ‘be’, ’ or not to ', ‘be’, ‘’]
从这里可以看出:
1. re.split()函数以正则表达式为分界点将字符串分隔开。
2. 如果正则表达式位于字符串的开头或者结尾,分割时则会出现一个空字符串。
re.finditer(re,string)
搜索字符串,返回一个匹配结果的迭代类型,每个迭代元素是match对象。
关于迭代类型,我还不太了解,之后会专门关于这个写一篇文章。
import re
text='To be or not to be'
print(re.finditer(r'be',text))
<callable_iterator object at 0x0000021A6B707320>
re.sub(re,str,string)
在一个字符串中替换所有匹配正则表达式的子串,返回替换后的字符串。
re:用于匹配的正则表达式
str:用于替换的字符串
string:操作对象字符串
import re
text='To be or not to be'
print(re.sub(r'be','@',text))
print(text)
To @ or not to @
To be or not to be
可以知道:
1.字符串的替换是全局范围的。
2.返回一个新的字符串,不影响原字符串。
符号表
1 | 7种特殊标记字符 |
---|---|
\ | 将下一个字符标记为一个特殊字符、或一个原义字符。 |
^ | 匹配输入字符串的开始位置。 |
$ | 匹配输入字符串的结束位置 |
* | 匹配前面的子表达式零次或多次。 |
? | 匹配前面的子表达式零次或一次。 |
+ | 匹配前面的子表达式一次或多次。 |
. | 匹配除换行符(\n、\r)之外的任何单个字符。 |
2 | 3种大括号重复字符 |
---|---|
{n} | 重复n次,n 是一个非负整数。匹配确定的 n 次。 |
{n,} | 重复n次或更多次,n 是一个非负整数。至少匹配n 次。 |
{n,m} | 重复n到m次,m 和 n 均为非负整数,n <= m。最少匹配 n 次且最多匹配 m 次。 |
3 | 其他字符 |
---|---|
? | 当该字符紧跟在任何一个其他限制符 (*, +, ?, {n}, {n,}, {n,m}) 后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串。 |
(pattern) | 匹配 pattern 并获取这一匹配。 |
(?:pattern) | 匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。 |
(?=pattern) | 正向肯定预查(look ahead positive assert),在任何匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 |
(?!pattern) | 正向否定预查(negative assert),在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。 |
(?<=pattern) | 反向(look behind)肯定预查,与正向肯定预查类似,只是方向相反。 |
(?<!pattern) | 反向否定预查,与正向否定预查类似,只是方向相反。 |
x|y | 匹配 x 或 y。 |
4 | 5种中括号范围字符 |
---|---|
[xyz] | 字符集合。匹配所包含的任意一个字符。 |
[0-9] | 匹配任何数字。 |
[^xyz] | 负值字符集合。匹配未包含的任意字符。 |
[a-z] | 字符范围。匹配指定范围内的任意字符。 |
[^a-z] | 负值字符范围。匹配任何不在指定范围内的任意字符。 |
5 | 4种大小写字母字符 |
---|---|
\b | 匹配一个单词边界,也就是指单词和空格间的位置。 |
\B | 匹配非单词边界。 |
\d | 匹配一个数字字符。等价于 [0-9]。 |
\D | 匹配一个非数字字符。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等等。 |
\S | 匹配任何非空白字符。 |
\w | 匹配非字母、数字、下划线。 |
\W | 匹配非(字母、数字、下划线)。 |
6 | 3种即换页、换行、回车符 |
---|---|
\f | 匹配一个换页符。 |
\n | 匹配一个换行符。 |
\r | 匹配一个回车符。 |
————————————————
此处原文链接:https://blog.csdn.net/qq_41185868/article/details/96422320
贪婪模式与非贪婪模式
我们刚刚在上面的符号表中看到有的符号对应是贪婪模式,有的对应的是非贪婪模式,那究竟什么是贪婪模式,什么是非贪婪模式呢?
.* 默认为贪婪匹配(尽可能多的匹配)
print(re.findall('a.*b','a1b4444444b'))
[‘a1b4444444b’]
.*? 为非贪婪匹配(尽可能少的匹配)
print(re.findall('a.*?b','a1b4444444b'))
[‘a1b’]
注: 分清’?’(英文问号)和’?’(中文问号)的区别!
语法
我们会发现,以上的字符串中一些是代词,一些是修饰词,修饰词为代词增添属性,进而决定匹配的模式。
小节
对于正则表达式的学习,还是需要多去看实用的代码,在应用的实践中得以提升。
给大家推荐一些网页:
python re模块
https://blog.csdn.net/qq_37482956/article/details/100081705
正则表达式最全详解!看完既会!
https://www.bilibili.com/video/av40628169?from=search&seid=15984293663220098868
python爬虫入门必备正则表达式详解
https://www.bilibili.com/video/av13282712?from=search&seid=1621323734684789947
结语
到这里,正则表达式的学习基本结束了,其实这一节学习以及前一节关于文件和文件夹的学习是为了下面关于网络爬虫的学习做准备,下一篇文章也就是准备写网络爬虫。
想了解文件和文件夹操作的可以看下我的上一篇文章:
python(1) 文件与文件夹的那些事
https://blog.csdn.net/qq_45014265/article/details/104180747
如果这篇文章中有什么小弟写错的地方或者什么写的不完善的地方,还请前辈们指出,以便我及时更改。