python之正则表达式

正则表达式是处理字符串的强大工具,可以实现字符串的检索,替换、匹配验证

常用的匹配规则如下:

模式描述
\w匹配字母、数字、下划线
\W 匹配不是字母、数字、下划线
\s匹配任意空白字符,等价于[\t\n\r\f]
\S匹配任意非空字符
\d匹配任意数字,等价于【0-9】
\D匹配任意非数字字符
\A匹配字符串开头
\Z匹配字符串结尾,如果存在换行,则匹配到换行前的字符串
\z 匹配字符串结尾,如果存在换行,同时还会匹配换行符
\G匹配最后完成匹配的位置
\n匹配一个换行符
\r匹配一个制表符
^匹配一行字符串的开头
$匹配一行字符串的结尾
.匹配任意字符,除了换行符,如果标记re.DOTALL,则可以匹配换行符
[…]表示一组字符,单独列出,比如[amk],匹配a、m或k
[^…]匹配不在[]中的内容,如[^abc]表示匹配除了abc之外的字符
*匹配0个或者多个表达式
+匹配1个或者多个表达式
?匹配0个或1个前面的正则定义的片段,非贪婪方式
{n}精确匹配n个前面的表达式
a|b匹配a或b
()匹配括号内的表达式,也表示一个组
{n,m}匹配n到m次由前面正则定义的片段,贪婪方式

python中的re库提供了整个正则表达式的实现,下面说下常用方法:

1、match():

向match()方法传入要匹配的字符串以及正则表达式,就可以检验这个正则表达式是否匹配字符串

match()方法会尝试从字符串的起始位置匹配正则表达式,如果匹配,返回匹配成功后的结果,如果不匹配,返回None,如图:

从上图中可以看出,match()方法中,第一个参数传入了正则表达式,第二个参数传入了要匹配的字符串,首先声明字符串content,里面包含字母、空格、数字,match()方法中添加正则,^hello表示匹配以hello开头,\s表示匹配一个空格,\d\d\d表示匹配三个数字,再写一个\s表示匹配一个空格,\d{4}表示匹配4个数字,在通过\s匹配空格,最后通过\w{5}匹配5个字母

注意:\d\d\d 也可以通过\d{3}的形式书写,更加简单方便,还可以写成\d+表示匹配1个或者多个\d

代码执行结果如下:

打印结果中,第一行为字符串的长度,第二行表示match()方法结果为SRE_MATCH对象,其中包含了匹配内容以及匹配范围,第三行为group()方法匹配的内容,第四行为span()方法匹配的范围,也就是字符串的长度

匹配目标

上面通过match()方法获得了匹配的字符串内容,如果想从此内容中提取一部分内容,应该怎么办呢?

此时可以使用()括号将想要提取的的子字符串括起来,()实际上标记了一个子表达式的开始和结束位置,被标记的每个子表达式会依次对应每一个分组,然后调用group()方法传入分组的索引即可获得提取结果,如图:

从上图中可以看出,正则表达式中匹配数字的\d+用()标记起来了,此时对应的分组索引为1号分组,如果后面还有多个标记,则对应2号分组,3号分组

代码执行结果如下:

结果可以看出group(1)成功提取了字符串内容,group()会输出完整的匹配内容,group(1)则可以在此内容基础上提取子字符串,也就是被()标记的内容,如果正则表达式后面还有()标记的内容,那么依次用group(2)、group(3)等来获取即可

通用匹配

上面写的正则表达式比较复杂,出现空白字符就用\s匹配,出现数字就用\d匹配,这样写比较复杂,还有一个万能匹配,可以用.*(点和星),其中.(点)可以匹配任意字符(除了换行符),*(星)表示匹配前面的字符无限次,所以他们组合一起可以匹配任意字符

修改上面的例子,通过.*来进行匹配,如图:

上图中的正则表示匹配以hello开头,shijie结尾,中间匹配任意字符的内容

贪婪和非贪婪

使用上面的.*匹配时,有时候匹配到的可能并不是我们想要的结果,如图:

上图中正则匹配使用()标记了一个子表达式用来匹配数字,其余部位用.*匹配任意字符,然后以shijie结尾,在通过group(1) 打印提取内容时得到的结果如下:

从上图中可以看出,匹配的结果为7,与原计划的1234567不符合,为什么呢?这里就涉及到一个贪婪匹配与非贪婪匹配的问题,在贪婪匹配模式下,.*会匹配尽可能多的字符,正则表达式中.*后面是\d+也就是至少匹配一个数字,并没有指定具体多少个数字,因此,.*就尽可能匹配多的字符,这里就将123456匹配了,给\d+留下一个可满足条件的数字7,因此最后得到的内容就是数字7

此时使用非贪婪匹配可以准确的获取到我们想要的内容,非贪婪匹配的写法为.*?,

注意看后面.*后面多了一个问号,通过下面的实例体验下功能:

从上图中可以看出,在.*后面加了一个?即为非贪婪模式匹配,打印结果如下:

上图中成功打印了想要的结果,非贪婪匹配就是尽可能匹配少的字符,当.*?匹配到hello后面的空白字符时,在往后就是数字了,而\d+恰好可以匹配数字,此时.*?将不会进行匹配,而是交给\d+来匹配,因此得到的结果正是想要的结果。

总结:在做匹配的时候,字符串中间尽量使用非贪婪匹配,以免出现匹配结果缺失的情况。

有一种情况要注意:如果匹配的结果在字符串结尾,使用.*?就有可能匹配不到任何内容,如图:

从上图可以看出,两个正则都是匹配abc,一个使用.*?,另一个使用.*,下面通过group(1)调用的时候可以发现,通过.*?匹配的内容为空,因此非贪婪匹配尽可能少的去匹配,而.*尽可能多的匹配,因此可以匹配到,打印结果如下:

修饰符

正则表达式可以包含一些可选的修饰符来控制匹配的模式,修饰符被指定为一个可选的标志,下面例子如下:

上图中,在字符串中加了换行符,正则表达式不变,用来匹配数字,打印结果如下:

从上图可以看出,运行直接报错,因此”.”(点)匹配的是除了换行符之外的任意字符,当遇到换行符的时候,.*?就不能匹配了,所以导致失败,此时可以在后面添加一个修饰符re.S,这个修饰符的作用是使”.”匹配包括换行符在内的所有字符,添加后”.”(点)就可以完成换行匹配了,如下:

打印结果中即可看到已经正确匹配了,如图:

还有一些修饰符,在需要的情况下也可以使用,如下:

修饰符描述
re.I匹配大小写不敏感
re.L做本地化识别(locale-aware)匹配
re.M多行匹配,影响^和$
re.S使.匹配包括换行符在内的所有字符
re.U根据Unicode字符集解析字符,这个标志影响\w、\W、\b、\B
re.X给与更灵活的格式将正则写的更易于理解

转义匹配

我们知道”.”可以匹配除了换行符之外的所有字符,那么如果字符串中包含”.”,此时就需要使用转义字符了,如下:

从上图中可以看出,通过转义字符已经成功匹配到了内容

2、search()

match()方法是从字符串的开头开始匹配的,一旦开头不匹配,那么整个匹配就失败了,例如:

上图中使用match()函数,正则从big开始匹配,运行结果如下:

从结果可以看出,从中间匹配不成功,返回结果为None,因此match()方法更适合用来检测某个字符串是否符合某个正则表达式的规则

search()方法在匹配的时候会扫描这个字符串,然后返回第一个成功匹配的结果,正则表达式可以是字符串的一部分,匹配的时候,search()方法会依次扫描字符串,直到找到第一个符合规则的字符串,然后返回匹配内容,如果搜索完了还没找到,就返回None。

将上述例子中的match()方法修改为search()方法,如图:

代码执行结果如下,已经成功打印出结果,如图:

3、findall()

上面介绍了search()方法,它可以返回匹配正则表达式的第一个内容,但是如果要获得

标签