本文主要涉及以下内容:
正则表达式基础
什么是正则表达式
不管是使用Windows的搜索工具,还是在word文档里面的查找和替换,肯定都用过*和?这种通配符。
如果想要在某个目录下找到自己写的笔记,我最常用的方法就是*.md就可以找到当前文件夹下所有的Markdown文件了;
正则表达式可以理解为超复杂的通配符,可以比通配符匹配的更为精准,正规一点的说法就是使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。
比如密码的限制(8位以上16位以内,不能出现特殊字符等等)、邮箱的格式,距离生活近一点的就是某手上的"你个萌萌",王者荣耀上的"你个**"。这些都是正则表达式的运用。
字符类
但是如果想查到一组限定的字符,比较原音字母(a, e, i, o, u),特殊字符(*, &, %, @)这怎么弄呢?
在正则表达式中使用[]将一组字符包裹起来,就到达了自己的需要,例如原音字符[aeiou],特殊字符[*&%@]即可完美的匹配任意一个!
元字符
如果想要匹配.,?,*这些符号,可以使用转义字符\,比如\.,其他元字符如下
正则中的重复
分支条件
用|把不同的规则分隔开,从左到右地测试每个条件,如果满足了某个分支的话,就不会去再管其它的条件了(就是如果有一个表达式为true,就不会执行后面的表达式,如果一直为false就一直执行)
来一个小栗子:中国地区的手机号样式一般如下
上面基本罗列出来了所有的手机号样式,现在假设有一个文本框,里面只能输入这种手机号,如果不符合格式,就会给出提示。正则表达式可以这样写?
首先这是一个有分支条件的式子,第一个式子依次是表示字符串的开始和结尾^ $,然后是'\('转义(,0,数字出现2到3次转义)数字出现7到8次。第二个式子依次是表示字符串的开始和结尾^ $,然后是0,数字出现2到3次[-\s]{1}是-符号或空格符号出现出现1次,数字出现7到8次。这样再配合编程语法就可以完成这样一个限制输入的内容!
贪婪与懒惰
贪婪(尽可能多)
a.*f(abcdefbcedf) → abcdefbcedf
懒惰(尽可能少)
a.*?f(abcdefbcedf) → abcdef
分组
在正则表达式中使用()进行分组,分组之后就可以对某个分组进行操作,比如重复某个分组,对引用某个分组,对某个分组进行命名,语法格式如下:
使用小括号进行分组,?P进行命名,如果想在后面进行引用的话使用(?P=name)来进行引用,示例如下
这样就可以完成一个简单的匹配IP地址的表达式!
零宽断言
零宽断言就跟它的名字一样,是一种零宽度的匹配,它匹配到的内容不会保存到匹配结果中去,最终匹配结果只是一个位置而已。
作用是给指定位置添加一个限定条件,用来规定此位置之前或者之后的字符必须满足限定条件才能使正则中的字表达式匹配成功。
零宽度正预测先行断言
(?=exp) 零宽度正预测先行断言,自身出现的位置的后面能匹配表达式exp,例如想要匹配以ing结尾的单词显示又不需要ing,这个时候就需要零宽度正预测先行断言;这么说比较抽象,直接上栗子
不匹配每个单词的ing的正则表达式?
零宽度正回顾后发断言
(?<=exp)零宽度正回顾后发断言,自身出现的位置的前面能匹配表达式exp,就是匹配前面的是某个字符且不匹配他,举个栗子
匹配re开头的单词不匹配re,此处用到的软件为RegexBuddy
负向零宽断言
(?!exp)零宽度负预测先行断言,断言此位置的后面不能匹配表达式exp,简单点说就是后面不能出现某个东东,我们来查找包含Windows的字符串,但是Windows后面不能是10
这里仅仅查找出来了3个!
零宽度负回顾后发断言
(?零宽度负回顾后发断言,来断言此位置的前面不能匹配表达式exp,Python中提供的re模块使Python拥有全部正则表达式的功能!
re模块
正则表达式的修饰符
查找单个匹配项:map
re.match 如果 string 开始的0或者多个字符匹配到了正则表达式样式,就返回一个相应的匹配对象 。如果没有匹配,就返回 None ;注意它跟零长度匹配是不同的。语法格式如下:
pattern是匹配的正则表达式,string是要匹配的字符串。flags是标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
匹配成功re.match方法返回一个匹配的对象,否则返回None,示例代码如下
开局导入re模块,r""表示为一个正则表达式,因为string2中间出现了一个数字5 所以不匹配!
查找单个匹配项:group
re.group是从Match对象中获取结果的,不过不分组默认为0,分组索引则从0开始(0是完整的一个匹配),如果多个分组,则第一个分组是1;也可以为其命名使用,示例代码如下
查找单个匹配项:search
re.search 扫描整个字符串找到匹配样式的第一个位置,并返回一个相应的匹配对象 。如果没有匹配,就返回一个 None ;注意这和找到一个零长度匹配是不同的。语法结构和match是一样的,示例代码如下
两者的区别为:re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回 None,而re.search匹配整个字符串,直到找到一个匹配。
查找单个匹配项:fullmatch
re.fullmatch如果整个 string 匹配这个正则表达式,就返回一个相应的匹配对象 。否则就返回 None ;注意跟零长度匹配是不同的。语法格式跟上面的也是一样的,示例代码如下
三者的区别:
match:字符串开头匹配
search:查找任意位置的匹配项
fullmatch:整个字符串要与正则表达式完全匹配
匹配对象
匹配对象总是有一个布尔值 True。如果没有匹配的话match() 和 search() 返回 None 所以可以简单的用 if 语句来判断是否匹配,示例代码
查找多个匹配对象——compile
re.compile将正则表达式的样式编译为一个正则对象,可以用于匹配,语法结构?
pattern是匹配的正则表达式,flags是标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
查找多个匹配对象——findall
re.findall在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。与match 和 search 不同的是 match 和 search 是匹配一次 findall 匹配所有。语法结构为
string 待匹配的字符串。
pos 可选参数,指定字符串的起始位置,默认为 0。
endpos 可选参数,指定字符串的结束位置,默认为字符串的长度
查找多个匹配对象——finditer
pattern 在 string 里所有的非重复匹配,返回为一个迭代器保存了匹配对象 。string 从左到右扫描,匹配按顺序排列。空匹配也包含在结果里。语法结构同match,示例代码
如果有超大量的匹配项的话,返回finditer的性能要优于findall,这就是列表和迭代器的区别,在第二十一天的Python中的生成式和生成器会提到!
分割——split
re.split方法按照能够匹配的子串将字符串分割后返回列表,语法结构
pattern:分隔的正则表达式
string:分隔的文本
maxsplit:分隔次数,maxsplit=1 分隔一次,默认为 0,不限制次数。
flags:标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
示例代码
与str模块的split不同的是,re模块的split支持正则
替换——sub
re.sub用于替换字符串中的匹配项,语法结构如下
pattern : 正则中的模式字符串。
repl : 替换的字符串,也可为一个函数。
string : 要被查找替换的原始字符串。
count : 模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
flags : 编译时用的匹配模式,数字形式。
到这里就可以完成一个某手的评论区,修改不良评论的小案例
替换——subn
行为与 sub() 相同,但是返回一个元组 (字符串, 替换次数).
escape
re.escape(pattern)转义 pattern 中的特殊字符。例如正则里面的元字符,示例代码如下
注:任意可能包含正则表达式元字符的文本字符串进行匹配,它就是有用的,不过容易出现错误,手动转义比较好!
purge
re.purge()用于清除正则表达式的缓存。