一、什么是正则表
正则表达式是一种用于匹配和操作字符串的强大工具。它可以用于检索、替换和验证字符串。正则表达式使用特定的语法来描述字符串的模式,然后用于查找符合该模式的字符串。
在Python中,可以使用re模块来使用正则表达式。re模块提供了一组函数,包括match()、search()、findall()、finditer()等,用于执行不同类型的匹配操作。
因为正则表达式也是用字符串表示的,所以首先了解如何用字符来描述字符,如果直接给出字符,就是精确匹配,但有一些字符加上转义符后就具有特殊含义
二、正则表达式元字符
1、\d : 可以匹配一个数字,例如:'00\d'可以匹配'007',但无法匹配'00A','\d\d\d'可以匹配'010'
2、\w :可以匹配一个字母或数字,例如:'\w\w\d'可以匹配'py3'
3、'.' :点可以匹配除\n,\r的任意单个字符,例如:'py.'可以匹配'pyc'、'pyo'、'py!'等等
4、\s :可以匹配任何不可见字符,包括空格、制表符、换页符等
5、\D :匹配一个非数字字符,等价于 [^0-9 ]
6、\S :匹配可见字符,[^\f\n\r\t\v]
7、\W:匹配任何非单词字符,[^A-Za-z0-9_ ]
8、\b :匹配一个单词的边界,指单词和空格间的位置
9、\B:匹配非单词边界,"er\B"能够匹配"er",但不能匹配"never"中的er
10、\f:换页符
11、\n:换行符
12、\r:回车符
13、\t:制表符
14、\v:垂直制表符
三、匹配长字符串
要匹配变长的字符,在正则表达式中,用 * 表示任意个字符(包括0个),用 + 表示至少一个字符,用 ? 表示0个或1个字符,用{n}表示n个字符,用{n,m}表示n~m个字符
[xyz]:字符集合,匹配所包含的任意一个字符,eg:[abc],即只能匹配abc中的一个字符
[a-z]:字符范围,匹配指定范围的任意字符,如:[A-Z],即可匹配一个A-Z之间的大写字母
[0-9]:数字范围,匹配指定范围的任意数字一个
*:匹配前面的子表达式任意次 ,即>=0
+:匹配前面的子表达式一次或多次,即>=1
?:匹配前面的子表达式一次或零次,即0或1
^:匹配输入的字符首,即限制开头,^\d表示必须以数字开头
$:匹配输入的字符尾,即限制结尾,\d$表示必须以数字结束
{n}:n是一个非负整数,匹配确定的n次
{n,}:n是一个非负整数,至少匹配n次
{n,m}:n是一个非负整数,最少匹配n次,最多匹配m次
A|B可以匹配A或B,所以(P|p)ython可以匹配'Python'或者'python'
在正则中 - 表示从什么到什么,[ ] 表示范围,例如:
[0-9a-zA-Z\_] 可以匹配一个数字、字母或者下划线
[0-9a-zA-Z\_]+ 可以匹配至少由一个数字、字母或者下划线组成的字符串,比如'a100','0_Z','Py3000'等
[a-zA-Z\_][0-9a-zA-Z\_]* 可以匹配由字母或下划线开头,后接任意个由一个数字、字母或者下划线组成的字符串,也就是Python合法的命名规则
[a-zA-Z\_][0-9a-zA-Z\_]{0, 19} 更精确地限制了长度是1-20个字符(前面1个字符,后面最多19个字符)
四、mach()可以判断正则表达式是否匹配
在正则表达式中,match()
是用于从字符串的起始位置开始匹配模式的函数。它尝试从字符串的开头匹配正则表达式模式,如果匹配成功则返回一个Match
对象,否则返回None
。
Match
对象包含了匹配的结果以及其他相关信息,可以通过调用group()
方法来获取匹配的字符串。如果正则表达式中包含了分组,可以通过传递分组索引或分组名称给group()
方法来获取特定的分组匹配结果。
例如:
re.match(r'^\d{3}\-\d{3,8}$', '010-12345')
调用match方法,左边需要传入一个正则表达式,右边为待匹配的字符串,如果能匹配上则返回:
<_sre.SRE_Match object; span=(0, 9), match='010-12345'>
re.match(r'^\d{3}\-\d{3,8}$', '010 12345') 无法匹配则返回空,即None
match方法通常会结合if选择结构进行判断:
五、re模块
re模块是Python中内置的用于处理正则表达式的模块。它提供了一系列函数和方法,用于对字符串进行匹配、搜索、替换等操作。通过导入re模块,可以使用正则表达式相关的功能,如编译正则表达式、匹配和搜索字符串、提取匹配结果等。re模块使得在Python中使用正则表达式变得非常方便和灵活。
注意:s = 'ABC\\-001' ,s类型为str,即Python最基本的字符串,由于'\'会对'\'进行转义,故对应的正则表达式字符串变成:'ABC\-001'
Python中为字符串提供了一种特殊的语法标记:r'abcdefg\hijklmn',如果使用r标记字符串,那么就不再需要考虑转义的问题了:s = r'ABC\-001',对应的正则表达式字符串不变:'ABC\-001'
推荐在Python中进行正则表达式匹配时,使用r前缀标记字符串
import re 使用前需要先导入re模块
六、用例解析
案例一、匹配一串电话号码
其中的r"\d{4}-\d{3,8}"表示的是电话号码,其中r表示防止双引号内有转置字符,\d表示一个数字,而后面的{4}则表示前一个\d的次数为4,即匹配四个数字,之后 - 表示特指这个字符,即必须匹配这个特定字符,之后的\d{3,8}则表示要匹配3个以上8个以下的数字,包含3和8
phone_num = "0551-1234567899" print(re.match(r"\d{4}-\d{3,8}", phone_num))
其打印结果为
案例二,用 split ( ) 切分字符串
strs = "a,b;c@d" print(re.split(r'[,;@]', strs))
正常我们都知道split的用法,便是 "1-2-3".split( ' - ' ),其打印结果为列表['1','2','3'],因为str自带的split方法,无法识别连续的空格, 但是re模块中的split方法无论多少个空格都可以正常分割,如上代码所述,即调用request类中的用法split,将字符串str中需要分隔的字符写出来分隔str字符串,得到的结果为 [a,b,c,d]
案例三、匹配出时间(分组group:元组形式打印)
除了简单地判断是否匹配之外,正则表达式还有提取子串的强大功能。用()表示的就是要提取的分组(Group),比如:^(\d{3})-(\d{3,8})$分别定义了两个组,可以直接从字符串中提取出区号和本地号码
如果正则表达式中定义了组,就可以在Match对象上用group()方法提取出子串来注意:group(0)永远是与整个正则表达式相匹配的字符串,group(1)、group(2)...表示第1、2、……个子串 t = "19:59:59" # 匹配出时间 # 分组使用的是在正则内部使用 括号 第几个括号就是第几个组别 print(re.match(r"([0-1]\d|2[0-3]):([0-5]\d):([0-5]\d)", t).groups())
解析其中的 r"([0-1]\d|2[0-3]):([0-5]\d):([0-5]\d)",
[0-1]表示匹配0到1的一个数字,\d表示匹配一个数字,他们俩联合起来就是匹配00到19的一个数字,后面的 | 则表示或的作用,指定了一个数2开头,0到3结尾的数字,即表示20到23之间的数字,[0-1]\d|2[0-3]他们两个用 | 符号或起来则表示匹配00到23之间的数字,之后的:号也表示指定匹配字符,以及 [0-5]\d 则同样表示0到5的数字后面结尾0到9的数字,合起来就是0到59的数字。
但是为什么要这么多呢,用一个普通的代码也可匹配例如:
t='19:59:59' reponse=re.match(r"\d\d:\d\d:\d\d",t) print(reponse)
其输出结果为:
同样可以匹配出时间,但是如果更改一下时间呢,代码如下:
t='95:66:59' reponse=re.match(r"\d\d:\d\d:\d\d",t) print(reponse)
其同样可以匹配成功,但是代码正确,逻辑不正确,时间的表示范围不对,所以必须要限制范围去匹配,使匹配更精准。
七、贪婪匹配
正则匹配默认是贪婪匹配,也就是匹配尽可能多的字符
例如,匹配出数字后面的0:
re.match(r'^(\d+)(0*)$', '102300').groups()
最终结果:('102300', '')
由于\d+采用贪婪匹配,直接把后面的0全部匹配了,结果0*只能匹配空字符串
必须让\d+采用非贪婪匹配(也就是尽可能少匹配),才能把后面的0匹配出来,加个?就可以让\d+采用非贪婪匹配:
re.match(r'^(\d+?)(0*)$', '102300').groups()
最终结果:('1023', '00')八、编译
当在Python中使用正则表达式时,re模块内部会干两件事情:编译正则表达式,如果正则表达式的字符串本身不合法,会报错,用编译后的正则表达式去匹配字符串
如果一个正则表达式要重复使用几千次,出于效率的考虑,可以使用compile方法预编译该正则表达式,接下来重复使用时就不需要编译这个步骤了,直接匹配:
import re # 导入模块 re_telephone = re.compile(r'^(\d{3})-(\d{3,8})$')#预编译 print(re_telephone.match('010-12345').groups()) # 进行匹配并返回所有组 print(re_telephone.match('010-8086').groups()) # 进行匹配并返回所有组