《精通正则表达式》读书笔记
2022-04-27 12:27:11 59 举报
AI智能生成
历时2个月,整理的正则表达式学习笔记。
作者其他创作
大纲/内容
正则表达式初体验
^和$ 定位一行的开头和一行的结尾
例子
注意:匹配模式的问题,如果没有指定匹配模式,默认只匹配第一行,或者最后一行
没有指定re.M 多行匹配的模式,^.*$并没有匹配结果。
如果要匹配所有行。
- re.findall('^.*$',string,re.M)
如果匹配“这”字开头的行
re.findall('^这.*',string,re.M)
['这是第一行,', '这是第二行,', '这是第三行,']
没有re.M的结果:re.findall('^这.*',string) 默认匹配第一行
['这是第一行,']
如果匹配“行”字结尾的行。
re.finall('.*行[,,]?$',string,re.M)
['这是第一行,', '这是第二行,', '这是第三行,', 'here is 第四行']
没有re.M的结果:re.findall('.*行[,,]?$',string)默认匹配最后一行
['here is 第四行']
注意二:注意re库中 search match fullmath findall之间的差异。
search,match,都是返回第一个匹配到的结果。后面即使符合条件,也不返回。
match只匹配开始,如果字符串没有匹配,则返回none,即使指定匹配模式为re.M,仍然只匹配第一行。
re.match('^这',string)
<re.Match object; span=(0, 1), match='这'>
search 扫描整个字符串,并返回第一次匹配的位置。
re.search('^h',string)多行文本,没有结果
但是指定了re.M是可以匹配到结果的:re.search('^h',string,re.M)
<re.Match object; span=(21, 22), match='h'>
findall
如果表达式中含有^$起止符的话,默认是^第一行,$最后一行。如果指定re.M匹配所有行。
如果表达式中不含有^$起止符的话,匹配所有行。
[ ] 字符组:匹配字符组里的一个字符
注意两个字符
^排除字符
[^A]
匹配一个未列出的字符。
-连字符
[a-z]
匹配a到z小写字母的任意一个。
例如:查找所有的H标签
<[hH][123456]>
<[hH123456]+>也能匹配,但是像<h1234>这种不符合要求的HTML标签也会被匹配到。
如果-位于首位,则当做普通字符。
. 匹配任意一个字符
| 多选结构
(a|b)匹配a或者b,a和b是独立的正则表达式。
例,找出html文件中所有的link标签和script标签里内容。
re.findall('<link.*>|<script.*>',string2)
结果:
量词:作用于之前紧邻的元素。
? 出现0次或者1次
如匹配color、colour。
colou?r
可以匹配color,colour。但是不能匹配colouur。
结果
匹配4和4th
4(th)?
结果:
+ 出现1次或者多次,最少出现一次
比如color和colour的匹配
colou+r
可以匹配colour和colouur,但不能匹配color,u至少要出现一次。
结果
子主题
s = "养鸡50只,养鸭70只,羊5头,龙虾5亩"
提取所有的养殖项目和规模。
结果
子主题
* “之前紧邻的元素出现任意多次,或者不出现也可以匹配”
匹配html文件中的空格。
link后不管有没有空格都可以匹配。
结果:
子主题
思考:很明显 <linkrel="">这样的标签是错误的,如果要匹配合法的html标签可以用+,link\s+ 至少出现一次空格才是合法的。
{n,m} 限定指定次数
例:匹配合法的身份证号:[1-9][0-9]{5}[12][0-9][0-9]{2}(0[1-9]|1[012])([0][1-9]|[12][0-9]|[3][01])\d{3}[0-9xX]{1}
[1-9]
第一位数字不能是0
[0-9]{5}
后面5位可以是任何数字
年份的匹配
年的匹配
[12] 年份的第一位目前只能出现1和2
[09]年份的第二位目前只能出现0和9
[0-9]{2}年份的第三第四位可以是任意2位数字
月的匹配
(0[1-9]|1[12])
如果月的首位为0,第二位可以出现1-9的任意数字
如果月的首位为1,第二位只可以出现0、1和2
日的匹配
([0][1-9]|[12][0-9]|[3][01])
如果日的首位为0第二位可以出现1-9的任意字符。
如果日的首位为1第二位可以出现0-9的任意字符
如果日的首位为3,第二位只能出现0和1
身份码的匹配
两种方法
\d{4}|\d{3}[xX]{1}
\d{3}[0-9Xx]{1}
命名组合和反向引用
命名组合:(?P<表达式别名>表达式)
?P<dup>/b/w+/b
命名一个名为dup的表达式
反向引用:(?P=表达式别名)
(?P<dup>/w+)(?P=dup)
重复了一次dup表达式,含义是查找拼写中出现了重词的情况。
结果:
(表达式) 捕获分组和不捕获分组(?:表达式)
"([0-9]+(\.[0-9]+)?([fFcC]))"
这里有三个括号结构如下:(()())
对应的有三个分组:
最外层的()
里面两层括号(),()
结果:
子主题
也可以使用[0]或者group(0) 来分别获取对应的分组。
re.search(pat,s)[0]
re.search(pat,s).group(0)
pat = "([0-9]+(?:\.[0-9]+)?([fFcC]))"
设置了不捕获的分组。使用findall/search/match (?:)标记的分组,将不显示在结果里。
结果:
子主题
环视
表达式2-1(?=表达式1)表达式2-2
顺序环视,从左到右查找文本,找到后标记位置,并以此位置为基础,通过表达式2两边查找。2-1左边匹配,2-2右边匹配。
表达式1:定位正则表达式。
表达式2-1 2-2:在表达式1定位后,往前(2-1)或者往后(2-2)查找文本,匹配符合表达式的文本。
例子1:
顺序环视匹配所有的有单词边界的david,找到位置后再匹配。
例子2:
锚点两边匹配
表达式2-1(?<=表达式1)表达式2-2
逆序环视,从右到左查找文本,找到符合表达式1的文本,标记位置,可以在这个位置前后
比较两个环视定位的位置差异
(?=david)
(?<=david)
图示:
正序在匹配文本的左边,逆序在右边。
综合案例:给数字千位加逗号。
思路:
以三个数字为一个单位进行编组,提高运行效率,该编组不需要被捕获(?:)
(\d{3})+
将这个作为环视条件
(?=(\d{3})+)
没有边界限定,结果是这样的。
环视是逐个字符环视,符合条件的位置都会被标记,直到最后三个数字,倒数第二个和倒数第一个不符合条件不标记。
所以要给每三个数字加一个边界限定 \b 或者$
结果是一样的
新问题出现:如果位数是三的倍数,首位也会被标记,这样不符合要求。
是这种情况
解决:这些位置要符合前面还有数字的条件。显然前面两个不符合。
从这个位置向前要有数字,所以用逆序环视(?<=\d)
结果
替换后的结果
思考:
能不能用\d来限定有一位数字的条件?
此时只会找到这个位置前的一个数字字符。通过将该数字字符替换成 2,也可以实现。前提是这个字符能被显式的捕获。
子主题
正则的匹配原理
NFA引擎的工作原理
字符串的构成
占有字符和零宽度:
占有字符
匹配流程
零宽度
匹配流程:
匹配流程
匹配流程
无论有多少子表达式,匹配结果是一样的。
控制权转换和指针移动
正则表达式:abc
匹配失败的情况
优先选择最左端的匹配结果
从字符串左侧开始
如果匹配成功,字符串和表达式指针前进1位,
依次,用c匹配字符c,匹配成功。字符串指针前进1位
同时,表达式指针到达结束位置,输出匹配结果,abc
同时,表达式指针到达结束位置,输出匹配结果,abc
继续匹配剩余字符,正则表达式 abc 开始匹配后续字符 d
a 无法匹配 字符 d 匹配失败。
如果是abca是什么情况?
标准量词是匹配优先的
标准量词
? 相当于 {0,1}
0或者1,优先匹配的是?量词的上限 1
+ 相当于 {1,}
1 或者 任意多,优先匹配的是+量词的上限 任意多
* 相当于 {0,}
零 或者 任意多
{n,m}
n到m次
标准量词的匹配流程
.*[0-9] 的匹配流程【量词+字符】
匹配成功后,输出匹配结果,然后,继续从,处继续匹配
先从 ,号开始,.* 会匹配所有字符,遇到 [0-9] 开始回溯寻找符合 [0-9] 的字符
如果没有,上面箭头向前进1位,至 字符 则 的位置,再用 .* 匹配所有字符,再回溯寻找符合 [0-9] 的字符
如此循环,直至文档结束。如果没有符合 [0-9] 规则的字符,匹配失败。
如果没有,上面箭头向前进1位,至 字符 则 的位置,再用 .* 匹配所有字符,再回溯寻找符合 [0-9] 的字符
如此循环,直至文档结束。如果没有符合 [0-9] 规则的字符,匹配失败。
注意,如果字符串,变成以上情况,回溯至1处,匹配成功,输出匹配结果,与上面匹配结果不同。
但原理相同, .* 会匹配所有字符,后面 [0-9] 会回溯,当首次找到符合 [0-9] 规则字符时,就返回结果。
但原理相同, .* 会匹配所有字符,后面 [0-9] 会回溯,当首次找到符合 [0-9] 规则字符时,就返回结果。
.*\d{2,4} 的匹配流程【量词+量词】
流程: .* 会匹配所有字符,当遇到 \d{2,4} 时,会回溯匹配,但此时 \d{2,4} 有连续量词,
根据匹配规则,先来先服务,此时量词范围 {2,4} 仅匹配量词范围的下限,即 2 个字符。
根据匹配规则,先来先服务,此时量词范围 {2,4} 仅匹配量词范围的下限,即 2 个字符。
如果后面是不确定的量词,遵循的规则时,先来先服务,后续量词仅匹配量词的下限。
.*(\d+)
+ 相当于{1,} 取下限 1,回溯匹配,结果只匹配1个字符。
.*(\d?)
?相当于{0,},取下限0,回溯匹配,结果为空
.*(\d*)
* 相当于{0,},取下限0,回溯匹配,结果为空
.*(\d{2,3})
匹配下限2,结果2个字符
.*(\d{4})
确定的量词,则会根据确定的数量匹配。
回溯的原理
回溯的概念
用 ".*" 匹配 “Regex”的过程
回溯的流程
如果,字符串是 "Regex"r 的话,回溯匹配的流程
.* 的陷阱
例如:如果匹配“”内的内容,使用".*",并不能得到预期的效果。
如图:回溯时从 .* 匹配的所有字符当中 ,从后面到前面依次匹配,当第一匹配成功,回溯匹配也就成功了。
如何解决:
第一种思路:修改匹配规则
“[^”]*”
匹配流程梳理可见,表达式“[^”]*”没有量词匹配失败回溯的过程,所以匹配效率比较高。
第二种思路:非贪婪匹配【忽略优先量词】
".*?"
这个更为常用。因为使用了忽略优先量词*?,所以在需要匹配".*?时,.*的状态会被忽略,继续匹配”,如果匹配成功就返回结果。
第三种思路:利用排除环视来去除指定字符
如图((?!要排除的字符).)* 也可以匹配除了<b>以外所有的字符。
注意:与[^<b>]不同,这个会把<b>拆分成<、b、>三个字符来排除,而不是作为一个整体<b>来排除。
匹配优先量词算法: ab?c 分别匹配 abc ac 和 abx的过程
ab?c 匹配 abc 的流程
ab?c 匹配 ac 的流程
ab?c 匹配 abx的 流程
忽略优先量词算法:".*?" 匹配:"a""b""c"
匹配优先算法 ".*" 的局限
忽略优先算法 ".*?" 可以克服以上局限
关于忽略优先量词的效率问题
固化分组和回溯
固化分组的思路
(\.\d\d[1-9]?)\d* 的匹配结果
(\.\d\d[1-9]?)\d+ 的匹配结果
解决思路:防止回溯。当 [1-9]? 匹配成功后就固化匹配结果,后续匹配不再回溯匹配
(\.\d\d(?>[1-9]?))\d+ 的匹配结果
使用固化分组的好处:提升匹配效率。
^(?>\w+):
如:如果没有固化分组,会一直尝试 \w+:,回溯,再尝试,直到匹配到最后一个字符。
如果使用固化分组,\w+会按照\w+的要求匹配所有符合条件的字符,并锁定,继续往后匹配,不管成功还是失败,都不会执行回溯——尝试的步骤。这样会显著减少循环运行的次数,可以提高匹配效率。
注意:python不支持固化分组功能
不过可以使用环视的功能,模拟固化分组。
匹配是三位小数的例子
可以改造成
^(?=(\w+))\1:
匹配一个单词的位置,并匹配这个单词\1,\1表示的是反向引用。也可以用
这样的表达式,结构清晰,但是要复杂一点
分支结构的原理
需要考虑两个问题:
问题一:分支结构的匹配是顺序匹配
需要慎重思考分支结构的顺序
如:匹配每个月的日期
规则:10以下 有09或者9,最大31。
这样可能会匹配不出想要的结果!因为所有的数字都会符合第一个分支,抛出结果后匹配结束,后面的分支基本没有机会匹配。
这称之为分支结构的陷阱
修改方案一:如果遇到多个分支且都能匹配相同结果的情况时,把能匹配到最短的结构放到分支结构的最后。
进一步完善方案:33的解决方案。用单词边界\b,甚至可以不用考虑分支结构的顺序了
问题二:引擎会按顺序匹配,不符合的匹配,会回溯到分支结构前。
环视
肯定顺序环视:(?=表达式H)
匹配流程
以上表达式为何会匹配失败?
否定顺序环视:(?!表达式H)
匹配流程
肯定逆序环视:(?<=表达式H)
匹配流程
否定逆序环视:(?<!表达式H)
匹配流程
环视小技巧
数字千位添加逗号
匹配替换的流程
匹配HTML标签中的内容
分析思路:
python的正则库
python正则语法
表示位置的字符
行的边界
^ 匹配一行的开始位置
$ 匹配一行的结束位置
单词的边界
\b 匹配空字符串,或者字符【大小写字符。数字。下划线】边界的位置。【常用于匹配单词边界】
匹配的位置在 \w和\W之间,\w开始或结尾的边界。注意以上的\W
如果用顺序环视可以模拟\b
\B 匹配非字符边界的位置
匹配以re打头的字符。
\b和\B的位置
\b的位置
\B的位置
文本的边界
\A 匹配文本开头的位置
只匹配文本开头的位置,而不是一行的开始位置,和^不一样!
一行开始的位置:^
\Z 匹配文本结束的位置
也是文本的结束位置,而不是一行的结束位置
任意位置
(?=表达式)肯定正序环视,根据表达式定位到符合表达式规则字符的左边位置。
如图,位置在匹配字符串的左边。
(?<=表达式) 肯定逆序环视,根据表达式定位到符合表达式规则字符的右边位置
如图,位置在匹配字符串的右边。
(?!表达式)否定正序环视,根据表达式定位符合表达式以外的位置。
刚好和(?=string)相反。除了指定的位置,其他位置都能定位。
否定正序环视的思考:
匹配除了表达式左边的所有位置
可以用这个特性,截断字符。
匹配合法html标签里的内容。
正常的思路
查找某个html标签里的内容,但是这个表达式也有弊端,如果有其他html标签的话,就无法匹配了。
简单粗暴的也不行
精巧的思路,用顺序否定环视 ((?!<p>).)*
所有<p>标签的左边的<将不会被匹配,其他的标签将不会被匹配<br>
改进一下
完善一下:
意义:[^<>]只能匹配一个列表中的所列字符外的所有字符。
如果想匹配多个字符串以外的所有字符,可以使用顺序否定环视的方法:表达式((?!表达式).)*
这里需要注意两点
如果想匹配完美的效果,前置的表达式和否定正序环视的表达式是一样的
当否定正序环视匹配了相对应的位置后,需要用.来匹配任意字符,如果没有,只匹配位置,并为匹配字符,环视将失去意义,所以 . 非常重要。 当然其他字符也可以,原则是位置后一定要匹配一个符合要求的字符。
(?<!表达式)否定逆序环视,匹配(?<=表达式)以外的所有位置。
匹配的位置刚好和(?<=string) 相反。
(?<=string)的结果
使用否定逆序环视也可以实现类似排除一组字符的匹配结果,与正序不一样的是 . 要放在(?>!表达式)的前面
在前面的推演
子主题
子主题
子主题
子主题
子主题
在后面导致>后面的字符无法匹配,最终只能匹配标签本身,后面的字符无法匹配
子主题
子主题
子主题
子主题
匹配一个字符
. 匹配任意字符
\w 匹配一个字符,包括unicode大部分字符、数字和下划线_
匹配所有的unicode字符中的一个。如果在模式中设置了ascll标志,则只能匹配[a-zA-Z0-9_]
指定了re.A的匹配模式,\w不能匹配中文
除非特别设置,python默认匹配所有unicode字符,包括中文。
默认支持中文字符的匹配
\W 匹配一个非字符【各种符号】
\d 匹配任意数字
\D 匹配任意非数字
\s 匹配任意一个空字符
\t 制表符
\v 垂直制表符
\n 换行符
\r 回车符
\0 空字符
\S 匹配任意非空字符
[ ] 匹配字符组内任意字符
[a-zA-Z_]
英文字符
[^a-zA-Z]
非英文字符
[^\t\n\v]
制表符、换行符、垂直制表符
[\b]
退格键
\ 转义
["]在python中直接表示双引号是错误的,所以需要在前面加一个转义
正确的做法
量词
匹配优先量词【贪婪匹配:尽可能多的匹配字符】
?
+
*
{m}
{m.n}
匹配最大值
忽略优先量词【非贪婪匹配:尽可能少的匹配字符】
??
+?
*?
{m,n}
匹配最小值
具体原理:请参阅匹配原理中的匹配优先和忽略优先
记录和捕获
记录:(?P<name>表达式)
给捕获的组重命名。如果没有命名,匹配到的组都是以123……来区分的,但是如果指定了,那么符合匹配条件的字符,将被保存在指定名称(name)的变量中。
捕获:(?P=name)
反向引用的两种用法
\1
(?P=name)
常见例子:找重复的词
用(?P<name>)和(?P=name)的方法
用\1的方法
不捕获:(?:表达式)
不记录捕获信息,这个对优化捕获结果,提高匹配效率费用有用,所以当遇到分组较多,()较多的情况时,可以考虑使用
条件和分支
| 分支语句
?(某个分组表达式的结果)如果有结果就用表达式1匹配|如果没有结果就用表达式2匹配
(?(1)yespattern|nopattern)
一个例子
思路:先匹配【路线】,在匹配【时间】,如果有【时间】字符串,向后匹配时间。如果没有,回溯到【路线】字符串后,获取没有时间的路线。
优化一下,就可以获取,确定时间的路线,和不确定时间的路线
确定的结果
不确定的路线
一个注意事项:(?P<判断>判断语句)(?(判断)语句1|语句2)
实际上语句2永远不会执行,因为只有(?P<判断>判断语句)匹配成功,才能继续向后执行语句。所以永远都是yes
所以要考虑(?P<判断>判断语句)没有匹配的情况,所以加一个?量词就可以了。(?P<判断>判断语句)?
标记
(?aiLmsux)
(?a)匹配ascii,\w只匹配英文、数字、_
(?u)匹配unicode,python默认匹配,所以\w,也会匹配中文
(?L)匹配本地字符,慎用!
(?i)忽略大小写
(?m)多行匹配
(?s)让.能匹配所有字符,包括换行符。
默认.不匹配换行符,如果(?s)标记,.就可以匹配换行符
(?x)允许多行表达式
可以让匹配表达式可读性更好!
组合使用
除了auL三个不能同时用,其他都可以组合使用
如:(?im)多行匹配和忽略大小写
子主题
re库的模块
pattern = re.compile(pat,flag=0)
将表达式编译成一个正则对象
正则对象的方法和属性
pattern.search(string[,start[,end]])
检查整个字符串,寻找第一个符合匹配规则的字符,如果找到返回一个匹配对象,找不到返回None。
如: ip = pater.search(string,start)
注意:re.search没有位置参数,只要找到一个,就会返回结果,后面的即使是符合规则,也不会被匹配到。所以如果想匹配后面所有符合匹配规则的字符,就可以使用正则对象的search方法,使用递归函数的方式,匹配所有符合匹配规则的字符串。
pattern.match(string[,start[,end]])
检查字符串开头,如果开头符合匹配规则,返回一个匹配对象,不符合,返回None
相比较search,match的匹配必须是开头符合规则,这个开头,受后面的pos,endpos指定:pos位置开始匹配,从pos位置开始符合规则就会返回匹配对象,不符合返回none
另一个例子:将key=value 形式的代码,转换成字典类型。
看图
子主题
看代码
pattern.fullmatch(string[start,[,end]])
只有整个字符串符合匹配规则,才返回匹配对象,不符合返回None
match和fullmatch,适合小单位字符串的匹配。比如匹配一个数字字符串是否是电话号码标准格式。fullmatch,则是精确匹配。
使用match的弊端,超出11位的手机号码,也会被错误的识别。
使用fullmatch,则可以避免。
pattern.split(string,maxsplit=0)
功能同re.split(pat,string,maxsplit=0,flag=0)
先用pat匹配字符,然后根据匹配的字符,分割字符串。
\W+匹配的结果
pattern.findall(string[,start[,end])
与re.findall(pat,string,flag=0),正则对象的findall方法,有start和end限定位置。
pattern.finditer(string[,start[,end]])
与findall不同的是,findall返回的匹配文本的列表,finditer返回的是匹配对象的迭代器。
finditer()
修改后的代码,提取合法ip地址的代码
findall()
pattern.sub(repl,string,count=0)
同re.sub(pat,repl,string,count=0)
一个例子,去除html文件中的标签
其中repl可以是函数,在定义这个函数时,传入的是这个正则表达式所返回的正则对象
比如:将将[p]标签转换为html标签。
关于sub中匹配的正则表达式:如果想同时匹配多个目标字符串,可以使用正则的分支语句。比如常见的置换文本。
置换代码
pattern.subn(repl,string,count=0)
跟sub功能一样,不一样的地方是,返回的结果不是匹配的字符串,而是,(置换后的字符串,替换的次数)构成的元组。
例子:一共匹配了12次
其他属性
pattern.flags
返回正则表达式的匹配模式。
pattern.groups
返回一个正则表达式有有几个分组。
pattern.groupsindex
如果表达式中有(?P<name>)的结构,则会返回一个字典,没有返回一个空字典
pattern.pattern
返回正则表达式
匹配合法的ip地址
使用递归,逐个匹配。
match = re.search(pat,string,flag)
扫描整个字符串,返回第一个符合正则表达式的结果,整个结果是一个匹配对象
匹配对象的方法和属性:<re.Match object; span=(0, 2), match='AB'>
返回匹配的内容
m.group(组名或者组索引)
例子
m.group(0),m.group(1),m.group('all'),m.group(2),m.group('d'),m.group(3),m.group('str')
m.group(0,1,2,3,4)
('12344hello*&#\n', '12344', 'hello', '*&#\n')
m['组名'] 或者 m[组索引]
m[0],m[1],m['all'],m[2],m['d'],m[3],m['str']
m[index]不支持切片操作。m[1:2]和m[1,2,3]是不支持的。
m.groups(default=None)
返回所有匹配的组
('12344hello*&#\n', '12344', 'hello', '*&#\n')
default参数
如果某一个组没有匹配到结果,可以用default来指定。
例子
m.groupdict(default=None)
返回所有匹配的组,返回的结果是一个字典。{组名:匹配的内容,}
例子
注意:如果正则表达式中没有自定义组名,这个方法,将会返回一个空字典
例子
返回匹配对象的一些属性
m.span(group)
返回某个组匹配到的开始和结束位置。如果没有匹配到返回(-1,-1)
如果没有指定group参数,返回的全局匹配结果的开始和结束位置。
m.start(group) 和m.end(group)
返回指定group匹配开始位置和结束位置。
m.pos和m.endpos
经常以(m.pos,m.endpos)出现,作为正则对象search/match/find/findall方法的位置参数。
m.re
返回一个正则对象
m.string
返回string的内容,即被匹配的字符串。
m.lastindex()
m.lastgroup()
返回最后一个匹配到组的名字。
search是一个找到即止的函数。
注意:search函数和正则对象的search方法的异同
re.search,参数中没有匹配字符串起始位置的参数。这个函数会扫描整个字符串,找到第一个符合正则表达式规则的文本,就停止了。
pattern.search(string,start,end) 正则对象的search方法,有扫描字符串起始位置的参数,使用这个参数,并配合递归函数,可以匹配整个字符串所有符合正则表达式规则的文本。
第一次代码
例子:用正则对象的search方法实现,类似finditer 的功能
使用生成器函数,修正上面的代码
查看
match = re.match(pat,string,flag)
扫描字符串的头部【不是整个字符串!】:字符串的开始处就必须符合规则才会返回匹配结果,否则就返回None,即使第2个字符开始,就已经符合匹配规则。
search和match的比较,match只扫描字符串头部,如果是匹配确定格式的文本,match的效率要高于search
也是一个也是找到即止的函数
match = re.fullmatch(pat,string,flag)
精确匹配!从开始到结束的位置,必须都匹配才能返回匹配结果
match和fullmatch的差异
match需要精确匹配头部
fullmatch则需要精确匹配头部和尾部
看一个例子
因为#的存在,不符合正则表达式,fullmatch没有结果。但是字符串头部满足匹配规则,有结果。
results = re.findall(pat,string,flag)
扫描全部字符串,返回所有符合匹配规则的结果文本。
findall返回的是一个列表。列表的每个元素,是由表达式中的捕获组【由表达式中的()决定的】所定义的元组
有括号的情况:
子主题
没有括号的情况,默认全局匹配
子主题
两者的区别
子主题
matchs = re.finditer(pat,string,flag)
扫描全部字符串,返回所有符合匹配规则的匹配对象
返回的是一个包含了所有匹配对象的迭代器
用递归函数和yield 写了一个类似finditer功能的函数
子主题
result = re.split(pat,string,maxsplit=0,flag=0)
根据正则表达式,寻找字符串中符合匹配规则的文本,然后基于找到的字符,将整个字符串拆分成一个列表。
同str.split()函数,str中的split函数,可供分割的字符必须是固定的。功能没有re.split强大。
比较两个split的差异
如图:显然使用正则split,结果要准确的多!
result = re.sub(pat,repl,string,count=0,flag)
根据正则表达式,扫描整个文档,对于符合正则规则的文本,用指定的文本或者函数【repl参数】进行替换
比字符串replace要强大的多的字符串替换功能。
例子:扫描文件夹,找出所有的电子书文件,提取书名,并制作一个书单
提取的原始字符串,带有扩展名
代码
结果
repl支持函数,让替换有了无限的可能。
result = re.subn(pat,repl,string,count=0,flag)
功能同sub,不同的是subn 返回了替换的次数。用于查找软件中:提示【一共完成了XXX处替换】
其他内容
匹配标记:
re.I 忽略大小写
也可以在表达式中使用(?i)来表示忽略大小写
re.M 多行匹配
也可以在表达式中可以使用(?m)来表示
re.D 强化 . 的匹配范围
re.X 支持多行正则表达式
也可以在表达式中使用(?x)
re.A 表达式只对ascii编码起作用。如果匹配的是纯英文的字符串,可以考虑使用该模式
re.L 匹配本地语言
其他功能
re.purge 清除正则表达式缓存
re.error(msg,pattern=None,pos=None)
返回一个正则错误对象
re.escape(pattern)
转义表达式中的特殊字符
应用场景,如果遇到需要用户输入的正则表达式时,如果表达式中有些字符需要转义,可以使用该函数,把用户输入表达式转义成合法表达式
但是\也会被转义,\w会被转义成\\w,应用时还需注意,当然也可以重写escape函数,如果遇到\w \W \d \D \s \S \t \v \n等字符时,不不转义,其他字符转义。
0 条评论
下一页