Python中正则表达式讲解

正则表达式是匹配字符串的强大武器,它的核心思想是给字符串定义规则,凡是符合规则的字符串就是匹配了,否则就是不合法的。在介绍Python的用法之前,我们先讲解一下正则表达式的规则,然后再介绍在Python中如何运用。

如果直接给出字符,那么就是精确的匹配,例如‘abc’当然是匹配’abc’了。

  • d可以匹配数字(0-9)
  • D和d相反,就是说只要不是0-9,都可以匹配
  • w可以匹配字母或者数字(0-9|a-z|A-Z)
  • W和w相反,就是说只要不是字母和数字,都可以匹配
  • s可以匹配空格, , , ,f
  • S和s相反
  • . 可以匹配除了 以外的任意字符

第一步先说这些内容,Python提供re模块,包含所有正则表达式的功能,看下面的程序演示:

#如何判断正则表达式是否匹配,使用re.match()
import re
a=re.match('d','1')
b=re.match('d','s')
print(a)
print(b)

输出:
<_sre.SRE_Match object at 0x000000000065A510>
None

这里说一下,如果match()方法匹配的话,返回一个Match对象,否则返回None
为了方便观察程序运行结果,我们使用if判断来输出结果,下面再看一个例子

import re
def is_match(a):
    if a!=None:
        print('yes!')
    else:
        print('no!')
a=re.match('d','123abc')
b=re.match('dd','123abc')
c=re.match('ddd','123abc')
d=re.match('dddd','123abc')
is_match(a)
is_match(b)
is_match(c)
is_match(d)

输出:
yes!
yes!
yes!
no!

现在来讲解上面的代码,我们知道d可以匹配一个0-9的数字,所以re.match(‘d’,’123abc’)中的d匹配的是字符串‘123abc’中的1,至于后面的’23abc’不用管它。一个d我只用匹配一个数字就可以了。re.match(‘dd’,’123abc’)中的两个d分别匹配的是字符串’123abc’中的‘1’和‘2’,后面的‘3abc’不用管。re.match(‘dddd’,’123abc’)中前3个d分别匹配的是‘1’,‘2’,‘3’,当第4个d去匹配‘a’的时候发现不能匹配,所以最后一个不能匹配上,输出None。再看几个例子体会下吧

为了减少代码量,下面的代码我会直接写主要的代码部分,输出结果用注释代替

a=re.match('w','123abc') #yes
b=re.match('w','abc123') #yes
c=re.match('w','Abc123') #yes
a=re.match('.','abc') #yes
b=re.match('.','Abc') #yes
c=re.match('.','12bc') #yes
d=re.match('.','*2bc') #yes
e=re.match('.','
2bc') #no

如果我们要匹配变长的字符,可以在d,w,s, . 的后面使用下面的符号
* 表示任意个字符(包括0个)
+表示至少一个字符
?表示0个或1个字符
{n}表示n个字符
{n,m}表示n-m个字符

a=re.match('d*','123') #yes
# *表示任意个字符,包括0个,所以d*可以匹配0个数字,所以match('d*','abc')可以匹配
b=re.match('d*','abc') #yes
c=re.match('d+','1abc') #yes
# +表示至少1个字符,d+表示至少1个数字,所以匹配不成功
d=re.match('d+','abc') #no
a=re.match('d?','123') #yes
b=re.match('d?','abc') #yes
c=re.match('d{3}','1234') #yes
#d{3}代表3个数字,而'12'只有2个,所以不匹配
d=re.match('d{3}','12') #no
#'12abc'前3个'12a'不全是数字
e=re.match('d{3}','12abc') #no
a=re.match('d{0,3}','abc') #yes
b=re.match('d{0,3}','12abc') #yes
c=re.match('d{0,3}','1234bc') #yes

还有更加精确的匹配,用[ ]表示范围,例如:
[0-9]匹配1个数字,和d一样
[a-z]匹配1个小写字母
[A-Z]匹配1个大写字母
_匹配下划线
[0-9a-zA-Z]可以匹配1个数字或者字母,等价于w
[0-9a-zA-Z _]可以匹配1个数字或者字母或者下划线,一般是变量的命名规则
[0-9] | [a-z]匹配1个数字或者小写字母,使用的是 | 符号
^表示以什么开头,例如^[0-9]就是以数字开头
$表示以什么结尾

a1=re.match('[0-9]','123') #yes
a2=re.match('[a-z]','abc') #yes
a3=re.match('[A-Z]','Abc') #yes
a4=re.match('[0-9a-zA-Z]','Abc') #yes
b1=re.match('[0-9a-zA-Z]','12bc') #yes
b2=re.match('[0-9a-zA-Z]','abc') #yes
b3=re.match('[0-9a-zA-Z]','张康abc') #no
b4=re.match('[0-9a-zA-Z\_]','_abc') #yes
a=re.match('^[0-9a-zA-Z\_][0-9]','a1bc') #yes
b=re.match('^[0-9a-zA-Z\_][a-z]','Abc') #yes
c=re.match('^[0-9a-zA-Z\_][A-Z]','1Bbc') #yes
d=re.match('^[0-9a-zA-Z\_][0-9]','1abc') #no
e=re.match('^[0-9a-zA-Z_]','_1bc') #yes
a=re.match('^[0-9a-z]+[A-Z]$','1234A') #yes
b=re.match('^[0-9a-z]+[A-Z]$','1234a') #no

正则表达式还可以用来切分字符串(切分字符串)

import re
a=re.split('s+','a  b c')
print(a)

输出:
['a', 'b', 'c']

关于字符串中的split()函数,不明白的请参考我的另一篇博文。上面的代码的意思是以空格为切分符,把字符串分成n段,并以list的形式返回。
如果还想把逗号加进去,让空格和逗号都变成分隔符,看下面的代码:

import re
a=re.split('[s\,]+','a  b c     ,d,f    e')
print(a)

输出:
['a', 'b', 'c', 'd', 'f', 'e']

正则表达式还可以用来提取子串(分组)

用( )表示的就是要提取的分组(Group),把想要提取的子串在正则表达式中用( )括起来,例如我要提取带区号的固定电话号的每一部分,看代码演示:

import re
a=re.match('(d{4})-(d{7})','0370-5163700')
g0=a.group(0)
g1=a.group(1)
g2=a.group(2)
print(g0)
print(g1)
print(g2)

输出:
0370-5163700
0370
5163700

d{4}匹配的是0370,因为我要提取它,所以用()括起来,代表一个分组
- 匹配的是 - ,因为这里 - 是特殊字符,需要转义,就像下划线需要转义 _,这里我不需要提取这个 - ,所以不用加括号。
d{7}匹配的是5163700,这是需要提取的第二个分组,所以需要括起来。
还有一点需要注意,无论什么时候,group(0)提取的都是原来的字符串,你要提取的分组从group(1)开始。

正则表达式的贪婪匹配

正则表达式匹配默认是贪婪匹配,也就是匹配尽可能多的字符,看个例子吧!

import re
a=re.match('^(d+)(1*)$','12345611111')
print('第一组:'+a.group(1))
print('第二组:'+a.group(2))

输出:
第一组:12345611111
第二组:

按照正常的理解d+应该匹配123456,1*匹配11111,但是由于正则表达式是默认贪婪匹配,d+匹配了全部数字。怎么才能不让它贪婪匹配呢,很简单,在后面加个问号?就可以了

import re
a=re.match('^(d+?)(1*)$','12345611111')
print('第一组:'+a.group(1))
print('第二组:'+a.group(2))

输出:
第一组:123456
第二组:11111

编译

在Python中使用正则表达式时,re模块内部会干两件事情:

  1. 编译正则表达式,如果正则表达式的字符串本身不合法,会报错;
  2. 用编译后的正则表达式去匹配字符串。

在编写网站的时候,有可能我们会对用户注册时输入的用户名或者邮箱等进行正则验证,那么一个正则表达式可能会匹配成千上万个用户名或者邮箱,每次都需要先编译后匹配,那么效率显得很低。那么为了提高效率,我们可以先编译正则表达式,只需要编译一次,然后用的时候再匹配。

import re
#由字母或者下划线开头,由数字,字母,下划线组成长度为6-20的字符串
re_c=re.compile('^[a-zA-Z\_][w\_]{5,19}$')
print(re_c.match('a123456789a123456789'))

输出:
<_sre.SRE_Match object at 0x000000000065A510>

编译后生成Regular Expression对象,由于该对象自己包含了正则表达式,所以调用对应的方法时不用再次给出正则串。

以上的内容只是正则表达式的九牛一毛,关于其他的正则表达式用法请读者自己查阅,如读者发现错误,欢迎指正。

原文地址:https://www.cnblogs.com/neuzk/p/9476429.html