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