正则表达式是一种用来匹配字符串的强有力的武器。它的设计思想是用一种描述性的语言来给字符串定义一个规则,凡是符合规则的字符串,我们就认为它“匹配”了,否则,该字符串就是不合法的。
一、如何描述字符
1、直接给出字符,精确匹配;
2、\d可以匹配一个数字;
3、\w可以匹配一个字母或数字;
4、. 可以匹配任意字符;
5、用 * 表示任意个字符(包括0个);
6、用 + 表示至少一个字符;
7、用 ? 表示0个或1个字符,也可以用来表示非贪婪匹配;
8、用 {n} 表示n个字符,用 {n,m} 表示 n-m 个字符;
9、\s可以匹配一个空格(包括Tab等空白符);
10、对特殊字符(如'-'),要用 '\'转义。
看如下的例子:
'00\d' 可匹配'001',但不能匹配 '00d';
'\d\d\d'可匹配'123';
'\d\w\w'可匹配'3gp';
'pi.'可以匹配'pip'、'pio'、'pi3'等;
'\d{4}\s+\d{5,8}'进行分析:\d{4}表示匹配4个数字,如'0376';\s+表示至少有一个空格,如匹配' '、' '等;\d{5,8}表示5-8个数字,如'9876543'。
二、复杂的匹配方式
1、可以使用[ ]进行更精确的匹配 ,如
(1)[0-9a-zA-Z\_]可以匹配一个数字、字母或下划线;
(2)[0-9a-zA-Z\_]+可以匹配至少由一个数字、字母或下划线组成的字符串,如'1bd'、'd_q0'、'_hi'等;
(3)[a-zA-Z\_][0-9a-zA-Z\_]*可以匹配由字母或下划线开头、后接任意个由数字、字母或下划线组成的字符串,这是python中合法变量的命名规则;
(4)[a-zA-Z\_][0-9a-zA-Z\_]{0, 19}对变量的长度进行更精确的限制。
2、| 可以表示选择性匹配,如A|B可匹配A或B,故(p|P)ython可以匹配'python'或'Python';
3、^表示行的开头,$表示行的结束,^\d表示必须以数字开头,\d$表示必须以数字结尾。
三、re模块
python提供了re模块,包含所有正则表达式功能,因python字符串本身使用\转义,故强烈推荐使用python的r前缀,这样在正则表达式字符串中不需要考虑转义的问题了。
在re模块中,match可判断字符串与正则表达式是否匹配,若匹配成功,则返回一个Match对象,否则返回None,如:
In [7]: import re
In [8]: re.match(r'^\d{4}\-\d{5,8}$', '0376-987654')
Out[8]: <_sre.SRE_Match object; span=(0, 11), match='0376-987654'>
In [9]: re.match(r'^\d{4}\-\d{5,8}$', '0376- 987654')
In [10]:
三、切分字符串
使用正则表达式进行字符串的切分,比使用固定的字符更灵活,请看下面几个例子:
正常的切分:
In [10]: 'a,b,,,c'.split(',')
Out[10]: ['a', 'b', '', '', 'c']
无法正确的将a, b, c区分开来,下面使用正则表达式进行切分:
In [13]: re.split(r'[\,]+','a,b,,,c')
Out[13]: ['a', 'b', 'c']
不论有几个','都可以正常的分割,下面加入空格及';',都可以正常的切分:
In [14]: re.split(r'[\,\s]+','a ,b , , , c')
Out[14]: ['a', 'b', 'c']
In [15]: re.split(r'[\,\;\s]+','a ;,b , ;, , c')
Out[15]: ['a', 'b', 'c']
四、分组
可以使用正则表达式进行字符串的分组,用()表示的就是要提取的分组(Group),如:
^(\d{4})-(\d{5,8})$定义了两个组,可以从中直接提取出区号和本地号码:
In [16]: g = re.match(r'^(\d{4})-(\d{5,8})$','0376-987654')
In [17]: g
Out[17]: <_sre.SRE_Match object; span=(0, 11), match='0376-987654'>
In [18]: g.group(0)
Out[18]: '0376-987654'
In [19]: g.group(1)
Out[19]: '0376'
In [20]: g.group(2)
Out[20]: '987654'
若是在正则表达式中定义了组,就可以在Match对象上用group()提取出字串,需要说明的是:
group(0)表示原始字符串,group(1)、group(2)...依次表示第1、2个字串。提取字串在实际中非常有用,下面是一个提取时间中时分秒的示例:
In [22]: t = '18:57:45'
In [23]: m = re.match(r'^(0[0-9]|1[0-9]|2[0-3]|[0-9])\:(0[0-9]|1[0-9]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])\:(0[0-9]|1[0-9
...: ]|2[0-9]|3[0-9]|4[0-9]|5[0-9]|[0-9])$', t)
In [24]: m.groups()
Out[24]: ('18', '57', '45')
五、贪婪匹配
正则表达式是贪婪匹配的,何为贪婪?就是尽可能多的匹配,如在下面的例子中,会匹配数字后面的'1':
In [25]: re.match(r'^(\d+)(1*)$','12098111111').groups()
Out[25]: ('12098111111', '')
这是因为\d+采用贪婪匹配,把后面的1全部匹配了,所有1*只能匹配空字符串。让\d+采用非贪婪匹配(即尽可能少的匹配),才可以把后面的1匹配出来,加?就可以让\d+采用非贪婪匹配的模式,看下面的示例:
In [26]: re.match(r'^(\d+?)(1*)$','12098111111').groups()
Out[26]: ('12098', '111111')
六、编译
在python中使用正则表达式,re模块内部有两个操作:
(1)编译正则表达式,若正则表达式语法有错误,则会报错;
(2)用编译后的正则表达式匹配字符串。
若一个正则表达式要重复使用成千上万次,从效率的角度考虑,应对正则表达式进行预编译,后面使用的时候就不需要警经历编译这个步骤,而是直接进行匹配,请看下面的示例:
In [28]: import re
In [29]: re_tel = re.compile(r'^(\d{4})-(\d{5,8})$')
In [30]: re_tel.match('0123-12345').groups()
Out[30]: ('0123', '12345')
In [31]: re_tel.match('0371-12090945').groups()
Out[31]: ('0371', '12090945')
正则表达式编译后生成 正则表达式对象(Regular Expression),已包含正则表达式,所以调用时不需给出正则表达式。
以上是正则表达式的基本知识,因为最近用的比较多,所以把廖雪峰老师的教程总结在此,便于以后用到时查看。
参考文献:廖雪峰-正则表达式