10.Python的一大利器:正则表达式

1、re模块

re模块中封装了很多正则表达式相关的函数,非常方便的使用正则表达式对字符串进行各种规则匹配检查,常用一个函数是match函数

  • match(patten,string)函数

用于对字符串进行正则匹配,patten表示正则表达式,string表示待匹配字符串,匹配成功返回Match对象,否则返回None

# match 函数 (从左开始匹配,没匹配成功,不会向后面匹配,匹配失败)
import re
str1 = "hello python"
str2 = "python hello python"
rs1 = re.match("python",str1)
rs2 = re.match("python",str2)
print(rs1) # None
print(rs2) # <re.Match object; span=(0, 6), match='python'>
  
#取值
print(rs2.group()) #python

2、单字符匹配

常用单字符匹配符号:

符号说明
.匹配除\n之外的任意字符
\d匹配0到9之间的一个数字,等价于[0~9]
\D匹配一个非数字字符,等价于[^0~9]
\s匹配任意空白字符,如:空格、制表符\t、换行\n
\S匹配任意非空白字符
\w匹配单词字符,包括字母、数字、下划线
\W匹配非单词字符
[]匹配[]中列举的字符
# 单字符匹配
import re
rs = re.match('.','1') # 匹配一个包含数字的字符串
print(rs.group())
rs = re.match('.','a') # 匹配一个包含单字符的字符串
print(rs.group())
rs = re.match('.','abc') # 匹配一个包含多字符的字符串
print(rs.group())

# 多字符匹配
rs = re.match('...','abc') # 匹配一个包含多字符的字符串
print(rs.group())

#匹配任意空白字符
rs = re.match("\s","\t")
print(rs)
rs = re.match("\s","\n")
print(rs)
rs = re.match("\s"," ")
print(rs)

# 匹配[]中的字符
rs = re.match("[hl]","hello")
print(rs)
rs = re.match("[Hh]","hello")
print(rs)
rs = re.match("[0123456789]","2")
print(rs)
rs = re.match("[0-9]","2")
print(rs)

3、数量表示

常用的数量表示字符:

符号说明
*匹配一个字符出现0次或者多次
+匹配一个字符至少出现一次,等价于{1,}
?匹配一个字符至多出现一次,就是出现0次或者1次,等价于{0,1}
{m}匹配一个字符出现m次
{m,}匹配一个字符至少出现m次
{m,n}匹配一个字符出现m到n次
# 匹配字符是否格式一样
str1 ='zhangsan,180,18'
str2 ='lisi,,20'
rs1 = re.match('\w+,[0-9]{3},\d+',str1)
rs2 = re.match('\w+,[0-9]{3},\d+',str2)
if rs1 != None:
    print(rs1.group())
else:
    print(rs1)
if rs2 != None:
    print(rs2.group())
else:
    print(rs2)

4、边界表示

边界表示符号:

符号说明
^匹配字符串开头
$匹配字符串结尾
# 边界
phone = '13456788765'
rs = re.match('1[3456789]\d{9}$',phone) #结束边界
print(rs)

phone = 'a13456788765'
rs = re.match('^[a-z]\d*',phone) #开始边界
if rs != None:
    print("手机号只能以数字开头")
else:
    print(rs.group())

5、转义字符

转义字符是将一些具有特殊功能的字符转换成普通字符,Python中的原生字符串可以解决多个斜杠问题,

原生字符串的表示方式就是在字符串前加一个字母r,例如:str=r'abc\\def'

#转义字符 (ip匹配)
str1 = '123.123.123.123'
rs1 = re.match('\w{3}.\w{3}.\w{3}.\w{3}',str1)
print(rs1) # <re.Match object; span=(0, 15), match='123.123.123.123'>
#使用q替代.
str2 = '123q123q123q123'
rs2 = re.match('\w{3}.\w{3}.\w{3}.\w{3}',str2)
print(rs2) #匹配的结果有问题 <re.Match object; span=(0, 15), match='123q123q123q123'>
# .使用转义字符
str2 = '123q123q123q123'
rs2 = re.match('\w{3}\.\w{3}\.\w{3}\.\w{3}',str2)
print(rs2)  # None

# 使用原生字符串
str = "qwer\\qwer"
print(str) #qwer\qwer 没使用打印结果

str = r"qwer\\qwer"
print(str) #qwer\\qwer 使用打印结果

6、匹配分组

常用的分组符号:

符号说明
|连接多个表达式,表达式之间是的关系,匹配`
()将括号中字符作为一个分组
\NUM结合()分组使用,引用分组NUM(表示分组编号)对应的匹配规则
(?P<name>)结合分组起别名
(?P=name)根据组名使用分组中的正则表达式
# 匹配QQ,163的邮箱
rs1 =re.match(r"\w{4,10}@(163|qq)\.com$","qwer123@163.com")
rs2 =re.match(r"\w{4,10}@(163|qq)\.com$","123456@qq.com")
print(rs1) # <re.Match object; span=(0, 15), match='qwer123@163.com'>
print(rs2) # <re.Match object; span=(0, 13), match='123456@qq.com'>

# 分组匹配网页标签
html_str1 ='<head><title>python</head></title>'
rs1= re.match(r'<(.+)><(.+)>.+</\2></\1>',html_str1)
print(rs1) #错误标签 打印结果None
html_str2 ='<head><title>python</title></head>'
rs2= re.match(r'<(.+)><(.+)>.+</\2></\1>',html_str2)
print(rs2) #正确 <re.Match object; span=(0, 34), match='<head><title>python</title></head>'>

7、内置函数

合理利用Python的内置函数,可以简化开发,提高开发

  • compile函数

编译正则表达式,返回一个正则表达式对象,可以多次重复使用

# compile函数
pattern =re.compile("\w{4,10}@163\.com$") #可复用的正则表达式对象
rs1 =re.match(pattern,'123456@163.com')
print(rs1) # <re.Match object; span=(0, 14), match='123456@163.com'>
  
rs2 =re.match(pattern,'qwe@163.com')
print(rs2) # None
  
rs3 =re.match(pattern,'zhangsan@163.com')
print(rs3) # <re.Match object; span=(0, 16), match='zhangsan@163.com'>
  
  • search函数

从左到右在字符串的任意位子搜索第一个被正则表达式匹配的子字符串

# search函数
rs = re.search("python","hello python ! ni hao ya")
print(rs) # <re.Match object; span=(6, 12), match='python'>
  • findall函数

在字符串中查找正则表达式匹配成功的所有子字符串,返回一个列表

# findall函数
str ='zhangsan:18012345432,lisi:19012345432'
list= re.findall(r"1[35789]\d{9}",str)
print(list) # ['18012345432', '19012345432']
  • finditer函数

在字符串中查找正则表达式匹配成功的所有子字符串,返回一个可迭代对象Iterator

# finditer函数
str ='zhangsan:18012345432,lisi:19012345432'
objs= re.finditer(r"1[35789]\d{9}",str)
for obj in objs:
    print(obj.group())
  • sub函数

将正则表达式匹配到的子字符串使用新的字符串替换掉,返回结果是替换后的新字符串,原字符串不变

# sub函数
str ='zhangsan:18012345432:20'
new_str=re.sub(":",",",str)
print(str)
print(new_str)

8、非贪婪与贪婪模式

8.1、贪婪模式:尽可能多地匹配字符

# 贪婪模式
rs1 =re.findall("python\d*","python2020") #任意多个数字
rs2 =re.findall("python\d+","python2020") #至少出现一个数字
rs3 =re.findall("python\d{2,}","python2020") # 至少出现两次数字
rs4 =re.findall("python\d{1,4}","python2020") # 出现1到4次数字
print(rs1) #['python2020']
print(rs2) #['python2020']
print(rs3) #['python2020']
print(rs4) #['python2020']

8.2、非贪婪模式:尽可能少地匹配字符串,启用方式是在表示数量的符号后面添加一个问号

# 非贪婪模式
rs1 =re.findall("python\d*?","python2020")
rs2 =re.findall("python\d+?","python2020")
rs3 =re.findall("python\d{2,}?","python2020")
rs4 =re.findall("python\d{1,4}?","python2020")
print(rs1) #['python']
print(rs2) #['python2']
print(rs3) #['python20']
print(rs4) #['python2']