Python正则表达式入门
一、基础的Python正则表达式
1、在Python 中使用正则表达式
正可谓人生苦短,我用Python。Python有个特点就是库非常多,自然拥有正则匹配这种常见的库,并且此库已经嵌入在Python标准库中,使用起来非常方便,只需要在代码中导入re模块即可。
import re
Python的re模块,使得Python具备了使用全部正则表达式的功能。
2、最基础正则表达式
正则表达式是一个以简单直观的方式通过寻找模式匹配文本的工具。
听起来比较复杂,实际非常简单,下面开始体验最简单的正则表达式。最简单的正则表达式是些仅包含简单字母数字字符的表达式——不包含任何其他字符,在这种情况下正则表达式完完全全就是一个正常的字符串。
举例说明,我们要匹配张明,那么张明这两个字符就是我们需要的正则表达式。
3.正则匹配函数
知道了最基础正则表达式,可是如何在python中使用了?首先我们学习第一个函数,search()函数,它的目的是接收一个正则表达式和一个字符串,并返回发现的第一个匹配的字符串。
import re
a = re.search(r'fox','the quick brown fox jumpred') #第一个参数为正则表达式,第二个参数为要处理的字符串
print(a.span()) # span方法获取的是正则表达式匹配到的位置
b = re.search(r'www','the quick brown fox jumpred')
print(b) #如果匹配不到则会返回None
输出如下:
(16, 19)
None
如何匹配到了,我们输出他在正则表达式中的位置,如果没有匹配到,则输出为空。
二、Python正则表达式-字符组
1、获得多个匹配信息
在很多常见的场景中需要进行多个匹配,比如在学生名单中过滤出所有的张姓学生的个数。
如果有这种需求咱们可以使用re模块中的findall 或者 finditer方法。两个方法的区别在于 findall 返回的是一个列表,finditer返回的是一个生成器。
l = re.findall(r'张','张三 张三丰 张无忌 张小凡')
print(l)
['张', '张', '张', '张']
在这个例子中,我们会发现findall返回了4个“张”,这是因为“张”字在后面的字符串中出现了4次。即findall返回了所有的匹配信息。
2、字符组
字符组允许匹配一组可能出现的字符,在正则表达式中用[]表示字符组标志,举个例子。
I like Python3 and I like python2.7
在这句话中,既有大写的Python,又有全部是小写的python。如果我要求都匹配出来,这时候该怎么操作了?这就是正则匹配中字符组的威力了。下面看下示例。
a = re.findall(r'[Pp]ython','I like Python3 and I like python2.7 ')
print(a)
['Python', 'python']
可以发现[Pp]既可以匹配大写的P也可以匹配小写的p,这里值的我们注意的是[Pp]仅匹配一个字符,他表示匹配在这个[]内的某一个。
三、Python正则表达式-区间与区间求反
1.区间
有一些常见的字符组非常大,比如,我们要匹配的是任意数字,如果依照上述代码,每次我们都需要使用[0123456789] 这种方式明显很不明智,而如果要匹配从a-z的字母,我们也这样编写代码的话,肯定会让我们崩溃。
为了适应这一点,正则表达式引擎在字符组中使用连字符(-)代表区间,所以我们匹配任意数字可以使用[0-9],所以如果我们想要匹配所有小写字母,可以写成[a-z],想要匹配所有大写字母可以写成[A-Z]。
可能我们还有个需求:匹配连字符。因为-会被正则表达式引擎理解为代表连接区间,所以这个时候我们需要对-进行转义。
示例:
a = re.findall(r'[0-9]','xxx007abc')
b = re.findall(r'[a-z]','abc001ABC')
c = re.findall(r'[A-Za-z0-9]','abc007ABC')
d = re.findall(r'[0-9\-]','0edu 007-edu')
print(a)
print(b)
print(c)
print(d)
执行结果如下:
['0', '0', '7']
['a', 'b', 'c']
['a', 'b', 'c', '0', '0', '7', 'A', 'B', 'C']
['0', '0', '0', '7', '-']
2.区间取反
到目前为止,我们定义的字符组都是由可能出现的字符定义,不过有时候我们可能希望根据不会出现的字符定义字符组,例如:匹配不包含数字的字符组。
a = re.findall(r'[^0-9]','xxx007abc')
b = re.search(r'[^0-9]','xxx007abc')
print(a)
print(b)
执行结果如下:
['x', 'x', 'x', 'a', 'b', 'c']
<re.Match object; span=(0, 1), match='x'>
可以通过在字符数组开头使用 ^ 字符实现取反操作,从而可以反转一个字符组(意味着会匹配任何指定字符之外的所有字符)。
接下来再看一个表达式:n[^e] 这意味着字符n接下来的字符是除了e之外所有的字符。
a = re.findall(r'n[^e]','final')
b = re.search(r'n[^e]','final')
c = re.findall('r[n[^e]]','Python')
print(a)
print(b)
print(c)
执行结果如下:
['na']
<re.Match object; span=(2, 4), match='na'>
[]
这里我们可以发现a和b匹配的是na,字符a因为不是e所以可以被匹配,而变量c的值为空,在这里正则表达式引擎只匹配到了字符串n的位置,而n之后没有任何可以匹配[^e]的字符了,所以这里也匹配失败。
[]
<re.Match object; span=(0, 6), match='master'>
四、Python正则表达式-快捷方式
- \w ,与 “任意单词字符”匹配,在Python3中,基本上可以匹配任何语言的任意单词。
- \d ,d即digit。在Python3中,它除了可以和[0-9]匹配,还可以和其他语言的数字匹配。
- \s快捷方式匹配空白字符,比如空格,tab、换行 等。
- \b 快捷方式匹配一个长度为0的字符串,但是,他仅仅在一个单词开始或结尾处匹配,这被称为词边界快捷方式。
| 快捷方式 | 描述 |
|---|---|
| \w | 于任意单词匹配 |
| \d | 与任意数字匹配 |
| \s | 匹配空白字符,比如,空格,换行 |
| \b | 匹配一个长度为0的字符串 |
a = re.findall(r'\w','学好Python 大展拳脚')
b = re.search(r'\w','python3')
c = re.search(r'\d','编号89757')
print(a)
print(b)
print(c)
执行结果输出如下:
['学', '好', 'P', 'y', 't', 'h', 'o', 'n', '大', '展', '拳', '脚']
<re.Match object; span=(0, 1), match='p'>
<re.Match object; span=(2, 3), match='8'>
这里findall会返回所有能匹配的值,search只会返回第一个匹配到的值。
2.快捷方式取反
之前提到了取反,快捷方式也可以取反, 例如对于 \w的取反为\W,可以发现将小写改写成大写即可。
注意:这里\B 有所不同,\b 匹配的是在单词开始或结束位置长度为0的子字符串,而\B匹配不在单词开始和结束位置的长度为0的子字符串。
a = re.findall(r'\Bmaster\B','masterxiao master xxx master abc') #单词字符后面或前面不与另一个单词字符直接相邻
b = re.search(r'master\B','masterxiao')
print(a)
print(b)
执行结果输出如下:
[]
<re.Match object; span=(0, 6), match='master'>
五、Python正则表达式-字符的开始与结束
在正则表达式中 用^ 可以表示开始,用 $表示结束,示例如下:
a = re.search(r'^python', 'python is easy')
b = re.search(r'python$', 'python is easy')
c = re.search(r'^python', 'i love python')
d = re.search(r'python$', 'i love python')
print(a.span())
print(b)
print(c)
print(d.span())
执行输出结果如下:
(0, 6)
None
None
(7, 13)
六、Python正则表达式-任意字符
值得注意的是:.字符只有一个不能匹配的字符,也就是换行(\n),不过让.字符与换行符匹配也是可能的,以后会讨论。示例如下:
a = re.findall(r'p.th.n','hello python re')
b = re.findall(r'p.....','学好 python 人见人爱')
print(a)
print(b)
输出:
['python']
['python']
七、可选字符
到目前为止,我们看到的正则表达式都是在正则表达式中的字符与被搜索的字符串中的字符保持1:1的关系。
不过有时,我们可能想要匹配一个单词的不同写法,比如color和colour,或者honor与honour。
这个时候我们可以使用?符号指定一个字符、字符组或其他基本单元可选,这意味着正则表达式引擎将会期望该字符出现零次或一次。
a = re.search(r'honou?r','He Served with honor and distinction')
b = re.search(r'honou?r','He Served with honour and distinction')
c = re.search(r'honou?r','He Served with honou and distinction')
print(a)
print(b)
print(c)
执行结果输出如下:
<re.Match object; span=(15, 20), match='honor'>
<re.Match object; span=(15, 21), match='honour'>
None
可以发现,在上述三个例子中,正则表达式为honou?r,这里可以匹配的是 honor 和 honour 不能匹配 honou,可以知道的是 ? 确定了前一个u是可选的。在第一个示例中,没有u,是没有问题可以匹配的;在第二个示例中,u存在这也没有问题;在第三个例子中,u存在但是r不存在,这样就不能匹配了。
八、重复区间
重复
到目前为止,我们只是学习了关于仅出现一次的字符串匹配,在实际开发过程中,这样肯定不能满足需求,比如要匹配电话号码,比如匹配身份证号,这些都是很多个数字组成的。
如果遇到这样的情况,我们可能期望一个字符组连续匹配好几次。
在正则表达式在一个字符组后加上{N} 就可以表示 {N} 之前的字符组出现N次。举个例子:
a = re.findall(r'[\d]{4}-[\d]{7}','张三:0731-8825951,李四:0733-8794561')
print(a)
输出为:
['0731-8825951', '0733-8794561']
重复区间
可能有时候,我们不知道具体匹配字符组要重复的次数,比如身份证有15位也有18位的。
这里重复区间就可以出场了,语法:{M,N},M是下界而N是上界。
举个例子:
a = re.search(r'[\d]{3,4}','0731')
b = re.search(r'[\d]{3,4}','073')
print(a)
print(b)
执行结果输出如下:
<re.Match object; span=(0, 4), match='0731'>
<re.Match object; span=(0, 3), match='073'>
通过上述代码,我们发现[\d]{3,4} 既可以匹配3个数字也可以匹配4个数字,不过当有4个数字的时候,优先匹配的是4个数字,这是因为正则表达式默认是贪婪模式,即尽可能的匹配更多字符,而要使用非贪婪模式,我们要在表达式后面加上 ?号。
a = re.search(r'[\d]{3,4}?','0731')
b = re.search(r'[\d]{3,4}?','073')
print(a)
print(b)
执行结果输出如下:
<re.Match object; span=(0, 3), match='073'>
<re.Match object; span=(0, 3), match='073'>
值得注意的是,上述代码这样子使用就只能匹配3个数字而无法匹配4个了。
九、开闭区间速写
1.##开闭区间
在实际生活中,我们经常会遇到一种场景,我们知道此处会填写什么格式,但是我们不确定填写的内容。比如说每月支出,我们知道此处一定是数字,但是不确定这个月支出了多少钱,是3位数,还是4位数,说不定这个月就花了10个亿。这时候我们可以用开区间来表示此范围,如下所示:
a = re.search(r'[\d]{1,}','我这个月花了:5元')
print(a)
输出为:
<re.Match object; span=(7, 8), match='5'>
2.##速写
在正则表达式中,我们可以通过开闭区间来应对此种重复次数没有边界的场景。但是如此常见的需求,为什么不简单一点用一个符号表示出来了,每次都这样写不累么?是的,不仅累而且影响阅读,因此在正则表达式中,推出了2个符号:
| 符号 | 含义 |
|---|---|
| + | 重复匹配1或多个 |
| * | 重复匹配0或多个 |
| 符号+用来表示重复一次到无数次,如下示范: |
a = re.findall(r'[\d]+','0731-8859456')
print(a)
执行结果输出如下:
['0731', '8859456']
重复符号 *
符号'*'用来表示重复 0次到无数次,如下示范:
a = re.findall(r'[\d]*','0731-8859456')
print(a)
执行结果输出如下:
['0731', '', '8859456', '']
为什么这一次的输出多了两个''?
因为在匹配-与末尾的字符时,没有匹配到一个数字,但是我们匹配到了0个数字,因此输出了空的字符串''。

正在表达式
浙公网安备 33010602011771号