(一)概念
正则表达式(Regular Expression,常简写为regex、regexp或RE),又称规则表达式。一组由字母和符号组成的特殊文本,通常被用来检索、替换那些符合某个模式(规则)的文本,即从文本中找出满足你想要的格式的句子。
在Python中一般需要导入re模块来实现其功能
(二)基础正则匹配知识
1.原子: 是正则表达式中最基本的组成单位,每个正则表达式至少要包含一个原子,常见原子有以下四类:
- 普通字符作为原子:比如数字、大小写字母、下划线等
- 非打印字符作为原子:字符串中用于格式控制的符号
- 通用字符作为原子:通用字符即一个原子可以匹配一类字符
- 原子表:定义一组地位平等的原子,匹配时取该原子表中任意一个原子进行匹配,原子表用 [ ] (字符种类,匹配方括号内的任意字符)表示,[^] 表示出了中括号里的原子其他原子均可匹配
2.元字符: 具有一些特殊含义的字符。可分为任意匹配元字符、边界限制元字符、限定符、模式选择符、模式单元等
3.模式修正: 在不改变正则表达式的情况下,通过模式修正符改变正则表达式的含义,从而实现一些匹配结果的调整等功能
4.贪婪模式与懒惰模式:
贪婪模式的核心是尽可能多的匹配,而懒惰模式的核心是尽可能少的匹配
通常情况下,若想在某些字符间匹配任意字符,“.*” 默认使用贪婪模式,“.?*”
(三)正则表达式常见函数
1.re.match()函数: 从源字符串的起始位置匹配一个模式
格式为:
re.match(pattern,string,flag)
参数pattern:表示对应的正则表达式
参数string:代表对应的源字符
参数flag:可选参数,代表对应的标志位,可以放模式修正符等信息
2.re.search()函数: 扫描整个字符串并进行对应的匹配
当使用re.match()或re.search()搜索成功时,会产生MatchObject对象,Python提供取得MatchObject对象内容的重要方法:
3.全局匹配函数: 将符合模式的内容全部匹配出来
- 使用re.compile() 对正则表达式进行预编译
- 编译后使用findall() 根据正则表达式从源字符串中将匹配的结果全部找出来
4.re.sub()函数: 实现替换某些字符串的功能
格式为:
re.sub(pattern,rep,string,max)
参数pattern: 为对应的正则字符串
参数rep:要替换成的字符串
参数string:源字符串
参数max:可选项,代表替换的次数,若忽略不写,默认将符合模式的结果全部替换
(四)正则表达式的Python实例解析
1.匹配电话号码:
说明:
正则表达式表示电话号码xx-xxxxxxxx的匹配模式为:r’\d\d-\d\d\d\d\d\d\d\d’,以连字符“-”进行括号分组,用小括号隔开群组重新划分表达式为:r’(\d\d)-(\d\d\d\d\d\d\d\d)‘简写为:r’(\d{2})-(\d{8})’。 {} 是一个量词, 常用来一个或一组字符可以重复出现的次数
使用re.rearch()执行比对时,可用group()传回比对符合的不同分组;可用groups()取得分组的内容
使用re.search()只传回第一个符合的字符串;使用re.findall()可传回所有匹配的字符串
import re
pattern = r'(\d{2})-(\d{8})'
string = "Please call my secretary using 02-26669999 or 08-25558888"
result = re.search(pattern,string)
phoneNum = re.findall(pattern,string)
print(result)
print(phoneNum)
print("===================================")
print("搜寻到的完整字符串:",result.group()) #传回比对符合的第一个分组
print("搜寻到的完整字符串:",result.group(0)) #同group()
print("搜寻到的区域号码字符串:",result.group(1)) #传回括号的第一组文字
print("搜寻到的电话号码字符串:",result.group(2)) #传回括号的第二组文字
print("===================================")
areaNum,localNum = result.groups() #取得分组的内容
print("搜寻到的区域号码字符串:",areaNum)
print("搜寻到的电话号码字符串:%s" %localNum) #两种输出格式
#进阶版匹配电话号码: 使用一对3个单引号(或双引号)将过长的正则表达式字符串拆成多行表达式。在正则表达式中加批注,必须将re.VERBOSE参数放在search()\findall()或compile()
import re
msg = '''02-26669999,(03)-25558888,05-29998888 ext 123,
12345678,02 29995555 ext. 12222'''
pattern = r'''(
(\d{2}|\(\d{2}\))? #区域号码
(\s|-)? #分隔符
\d{8} #电话号码
(\s*(ext|ext.)\s*\s{2,4})? #2-4位数的分机号码
)'''
phoneNum = re.findall(pattern,msg,re.VERBOSE)
print(phoneNum)
2.匹配.com或.cn后缀的URL地址:
规律:“://”和“.com”或“.cn”结尾是固定的,两者之间不能出现空格,故可写为[^\s]*,在“://”之前必须要有内容,此时至少要有一次重复,故用“+”而不用“ * ”,内容是任意的字母组合,包括大小写,所以可写为[a-zA-Z],组合起来的正则表达式为:
[a-zA-Z]+://[^\s] *[.com|.cn]
import re #导入re库
pattern = "[a-zA-Z]+://[^\s]*[.com|.cn]" #正则相应的正则表达式
string = "<a href='http://www.baidu.com'>百度首页</a>" #设置要检索的字符串
result = re.search(pattern,string)
print(result)
print("搜寻到的字符串的起始位置:",result.start())
print("搜寻到的字符串的结束位置:",result.end())
print("搜寻到的字符串的(起始,结束)位置:",result.span())
print("搜寻到的字符串:",result.group())
3.匹配电子邮件地址:
import re
pattern = "\w+([.+-]\w+)*@\w+([.-]\w+)*\.\w+([.-]\w+)*" #匹配电子邮件的正则表达式
string = "<a href='http://www.baidu.com'>百度首页</a><br><a href='mailto:c-e+o@iqi-anyue.com.cn'>电子邮件地址</a>"
result = re.search(pattern,string)
print(result)
4.匹配IP地址:
import re
ip = '196.128.25.1' #0-255.0-255.0-255.0-255
#pattern = r'\d\d\d\.\d\d\d\.\d\d\.\d' #知道每位的个数,匹配xxx.xxx.x.x
#pattern = r'\d{3}\.\d{3}\.\d{2}\.\d' #简写
#pattern = r'(([01]\d\d|2[0-4]\d|25[0-5])\.){3}([01]\d\d|2[0-4]\d|25[0-5])' #匹配xxx.xxx.xxx.xxx
pattern = r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])'
result = re.search(pattern,ip)
print(result)
注意:
表达式在数字超过200之后就只能匹配上前两位了,而单独使用2[0-4]\d和25[0-5]匹配超过200之后的数字又是可以的,{0,1}匹配0次或1次。这样就很明显了,因为匹配0-199的表达式排在最前面所以先执行的是r’[01]{0,1}\d{0,1}\d‘,匹配超过200的数时,比如’205‘时,’匹配百位数2的时候,[01]{0,1}会判断为匹配0次,然后直接进行下一个\d{0,1},这样就会匹配到’205’的2,最后在匹配\d,直接匹配到’205’的0,到此,匹配结束,返回’20’