注:此为慕课网Python(不打广告)视频的观看笔记,只做记录之用,并未勘误。
正则表达式
定义:
是一个特殊的字符序列,一个字符串是否符与此字符序列相匹配
作用:
可以快速检索文本、实现一些替换文本的操作
场景:
检查一串数字是否是电话号码
检查字符串是否是Email格式
把文本中指定单词替换为其他单词
示例:
判断下列字符串是否包含Python
a = 'C|C++|Java|C#|Python|JavaScript'
print(a.index('Python')>-1)
# True
print('Python' in a)
# True
上述是使用python内置的函数来实现字符串查找等功能
使用常量正则表达式:
使用re的方法: re.findall('正则表达式','所匹配的字符串')
import re
a = 'C|C++|Java|C#|Python|JavaScript'
print(re.findall('Python',a))
#输出:['Python']
print(re.findall('C',a))
#输出:['C', 'C', 'C']
#判断是否包含字符串:
print( len(re.findall('Python',a)) > 0 ) #输出True
常量正则表达式:规则单一,没有体现出正则的强大
正则的强大之处就在于构造有意义的规则
构造有规则的正则表达式:
示例:
提取字符串中的所有数字
方法一:循环遍历每个字符
方法二:构造正则,使用findAll方法 :'\d'表示0~9
'Python' - 普通字符
'\d' - 元字符之一
'\D' - 去掉数字
代码:
import re
a = 'C1|C++2|Java3|C#4|Python5|JavaScript6'
print(re.findall('\d',a))
#['1', '2', '3', '4', '5', '6'] 找出了全部数字
print(re.findall('\D',a)) 去掉数字
#['C', '|', 'C', '+', '+', '|', 'J', 'a', 'v', 'a', '|', 'C', '#', '|',
# 'P', 'y', 't', 'h', 'o', 'n', '|', 'J', 'a', 'v', 'a', 'S', 'c', 'r',
# 'i', 'p', 't']
元字符很多,不需要记忆元字符,要学会自由组合
更重要的是:模式 - 任意的、A或B、等等
字符集
形式:
中括号 [xyz]:x或y或z
示例:
找出中间一个字符是c或者是f的字符串
代码:
import re
s = 'abc,acc,adc,aec,afc,apc'
print( re.findall( 'a[cf]c',s ) ) #['acc', 'afc']
#输出: a [cf] c
# 借助a定界 表示a或f 借助c定界
# 普通字符 元字符 普通字符
中括号 [^xyz]:除去x或y或z
代码:
print( re.findall( 'a[^cf]c',s ) ) #['abc', 'adc', 'aec', 'apc']
中括号 [a-d]:a或b或c或d
代码:
print( re.findall( 'a[a-c]c',s ) ) #['abc', 'acc']
概括字符集
形式:
类似'\d',表示囊括所有的数字,
其他相同作用的规则:
'\d' = 字符集'[0-9]'
'\D' = 字符集'[^0-9]'
场景:
匹配字符串中的各类字符
示例:
import re
a = 'C1|C++2|Java3( C#4\n)Python5_JavaScript6'
print( re.findall( '\w',a ) ) #返回单词字符,字母,数字,和下划线
#['C', '1', 'C', '2', 'J', 'a', 'v', 'a', '3', 'C', '4', 'P', 'y', 't',
# 'h', 'o', 'n', '5', '_', 'J', 'a', 'v', 'a', 'S', 'c', 'r', 'i', 'p',
# 't', '6']
print( re.findall( '\W',a ) ) #返回非单词字符
#['|', '+', '+', '|', '(', ' ', '#', '\n', ')']
使用中括号的形式匹配字母和数字
print( re.findall( '[0-9a-zA-Z]',a ) )
print( re.findall( '\s',a ) ) '\s' 匹配空白字符
#[' ', '\n']
print( re.findall( '\S',a ) ) '\S' 匹配非空白字符
print( re.findall( '.',a ) ) '.' 匹配除\n之外的字符
第一种数量词
形式:
{N} 或者 {M,N}
示例:
import re
a = 'tom12,gimmy*77,kit_001,jack,yang'
print(re.findall('[a-z][a-z][a-z]',a))
#输出['tom', 'gim', 'kit', 'jac', 'yan']
这里重复使用三次中括号字符集完成了匹配长度为三的字符
print(re.findall('[a-z]{3}',a))
#输出['tom', 'gim', 'kit', 'jac', 'yan']
上述使用大括号:{},使用数量词来完成重复,结果与上述一致
print(re.findall('[a-z]{3,6}',a))
#输出['tom', 'gimmy', 'kit', 'jack', 'yang']
如果需要匹配出全部英文单词,即匹配出长度为3-5的字符,可以使用{x,y}来限定重复次数
此处的匹配是:贪婪的,检测到gim之后,并不停止,因为没有达到最大限定5,故还会继续匹配,一直到匹配到gimmy之后才停止
python默认是贪婪的匹配
非贪婪的模式匹配正则:{}?
print(re.findall('[a-z]{3,6}?',a))
#输出['tom', 'gim', 'kit', 'jac', 'yan'],此处匹配到3字符后就停止了
第二种数量词
形式:
*, +, ?
含义:
* 匹配*号前的字符0次或者无限多次
+ 匹配+号前的字符1次或者无限多次
? 匹配?号前的字符0次或1次
示例:
import re
a = 'to_tom12tomy*77tomyy,kit_001,jack,yang'
print(re.findall('tomy*',a))
#输出['tom', 'tomy', 'tomyy']
解释:
tom 成功匹配t,o,m,匹配y不成功,即成功0次
tomy 成功匹配t,o,m,y
tomyy 成功匹配t,o,m,y,y又匹配成功,因为可以无限次,故含有y
print(re.findall('tomy+',a))
#输出['tomy', 'tomyy']
解释:
to 没出来,因为to之后的my没匹配成功,即成功-1次
tom 没出来,因为tom之后的y没匹配成功,即成功0次
tomy 成功匹配t,o,m,y
tomyy 成功匹配t,o,m,y后,后续匹配y,因为y在tomy内,故成功
print(re.findall('tomy?',a))
#输出['tom', 'tomy', 'tomy']
解释:
to 没匹配出来,因为匹配失败2次,即匹配成功-1次
tom 匹配出tom,因为匹配到tom之后再匹配'y'没有匹配到,即匹配成功0次
tomy 成功匹配t,o,m,y
tomy 注意tomyy匹配为tomy,因为成功匹配t,o,m,y后,y虽又匹配成功,但已经是第二次,故丢弃
print(re.findall('tomy{1,2}',a)) #使用{}作为数量词限定
#输出['tomy', 'tomyy']
print(re.findall('tomy{1,2}?',a)) #非贪婪
#输出['tomy', 'tomy']
<< 更多精彩尽在『程序萌部落』>>
<< https://www.cxmoe.com >>
边界匹配符
形式:
^ 、 $
场景:
验证字符串长度:4-8位
示例:
import re
a = '11345610000'
print(re.findall('\d{4,8}',a))
#输出['12345610']
这样可以匹配出4-8位字符,但是判断不了原串是否为4-8位
此处应该使用面向字符串的匹配:
边界匹配:^表达式$,将‘表达式’作为整体匹配
示例:
print(re.findall('^\d{4,8}$',a))
#输出[]
边界符的作用:
不用边界符时
print(re.findall('00',a))
#输出['00', '00']
使用边界附 ^ 从字符串开始的位置开始匹配
print(re.findall('^00',a))
#输出[]
因为字符串开头为1,故匹配失败
使用边界附 $ 从字符串末尾的位置开始匹配
print(re.findall('00$',a))
#输出['00']
字符串结尾为0000,这里只匹配到0,0就结束
组
形式:
()
场景:
判断字符串是否包含连续!N个子串
示例:
例如判断串中是否存在三个'to'
代码:
import re
a = 'to_tom12tomy*77tomyy, kit_001, jack, yang_tototo'
print(len(re.findall('(to){3}',a))>0)
#输出True 表示存在tototo,连续匹配 t且o 三次
中括号[]和小括号()的区别:
[xyz]:x或y或z
(xyz):x且y且z
匹配模式
形式:
re.I re.S
示例:
import re
a = 'to_tom\ntomy*77tomyy, kit_001, jack, yang_tototo'
print(re.findall('Tom',a))
#[] 匹配不到tom,大小写不符
使用模式:添加第三个参数:
print(re.findall('Tom', a, re.I ))
#['tom', 'tom', 'tom']
如何匹配'tom\n' ?
print(re.findall('Tom.', a, re.I ))
#['tomy', 'tomy'] 没匹配出来
使用添加模式re.S
print(re.findall('Tom.', a, re.I | re.S ))
#['tom\n', 'tomy', 'tomy']
这里由于匹配了模式re.S,所以匹配出了\n字符
sub()
形式:
re.sub(表达式,替换成,原串))
场景:
替换 字符串
示例:
简单替换(与内置方法replace类似)
import re
a = 'to_tomtomy*77tomyy, kit_001'
print(re.sub('tom','Tom',a))
# to_TomTomy*77Tomyy, kit_001
print(re.sub('tom','Tom',a, 1))
#to_Tomtomy*77tomyy, kit_001
#注意:使用了count=1参数,只替换了第一个tom
#简易替换:
print(a.replace('tom','Tom', 1))
#to_Tomtomy*77tomyy, kit_001
#同样是替换了第一个tom
高级替换:
sub的强大之处,在于可以附加一个函数参数
示例:
def convert(value): #注意需要带一个参数
print(value)
print(re.sub('tom',convert,a))
#输出
#<_sre.SRE_Match object; span=(3, 6), match='tom'>
#<_sre.SRE_Match object; span=(6, 9), match='tom'>
#<_sre.SRE_Match object; span=(13, 16), match='tom'>
#to_y*77yy, kit_001
注意上述替换后结果中tom消失了,而且传入函数的参数为对象:
三个对象:表示进行了三次字符串匹配
span(3,6)表示第一次tom字符串的起始边界为3,结束后的边界为6
通过函数进行动态替换,替换为return的值
示例:
def conver(value): #注意需要带一个参数
match = value.group()
#value.group() 表示匹配成功时传进函数的字符串
return '['+match+']'
print(re.sub('tom',conver,a))
#输出:to_[tom][tom]y*77[tom]yy, kit_001
进一步复杂的替换:
示例:
替换所有大于等于50的数字为 [BIG] ,小于的剔除
代码:
import re
a = 'to_to5mtomy*77tomy65y'
def conver(value): #注意需要带一个参数
match = value.group()
print(match)
if( int(match) >= 50): #注意转换类型
return ' [BIG] '
return ''
print(re.sub('\d+',conver,a))
#输出:
#5
#77 注意,此处77作为整体传入,不会分两次传入7,7
#65
#to_tomtomy* [BIG] tomy [BIG] y ,完成替换
search(),match()
地位:
这是re模块正则匹配的三种方法的除findall之外的其余两种
形式:
re.match
re.search
示例:
import re
a = '1_to_to5mtomy*77tomy65y'
print(re.match('\d',a))
#输出<_sre.SRE_Match object; span=(0, 1), match='1'>
match()特点:
从字符串首字符开始匹配,如果失败,将返回None,object; span=(0, 1)其实就是'1'
print(re.search('\d',a))
#输出<_sre.SRE_Match object; span=(5, 6), match='5'>
search()特点:
将尝试搜索字符串,将找到的第一个字符返回,注意object; span=(5, 6),其实就是字符'5'
对于返回的object,有相关操作方法
group()方法:返回匹配的字符、字符串
示例:
print(re.search('\d',a).group()) #输出 1
span()方法:返回匹配结果在原串中的位置
示例:
print(re.search('\d',a).span()) #输出 (0, 1)
比较与findall方法,他们只要匹配成功就会停止匹配
比较与findall方法,他们会返回对象
print(re.findall('\d',a)) #输出['1', '5', '7', '7', '6', '5']
匹配返回对象的方法 分组:group()
场景:
例如取出下面的时间信息
示例:
import re
a = '#2002 2017-10-30 11:12:34 #!'
首先使用普通字符 定界,这里的边界是'2002 '和' #!'
print(re.search('2002 \w #!',a).group())
# 报错,因为seach无返回值,None.group()会报错
print(re.search('2002 \w* #!',a).group())
# 报错,因为seach无返回值,None.group()会报错
print(re.search('2002 .* #!',a).group())
# 输出:2002 2017-10-30 11:12:34 #!
这里并没有只返回中间内容,连边界也返回了
print(re.search('2002 .+ #!',a).group())
# 同样输出:2002 2017-10-30 11:12:34 #!
带参数的group()
注意:
group(parameter): group() = group(0)
group(0):永远记录完整匹配结果
group(N):N>0,记录第N个分组
示例:
print(re.search('2002 (.+) #!',a).group(1))
#输出:2017-10-30 11:12:34
注意上述括号(),表示一个分组,使用group(1),表示返回第一个分组
使用findall完全可以实现:
print(re.findall('2002 (.+) #!',a))
#输出:['2017-10-30 11:12:34']
另:groups()
print(re.search('2002 (.+) #!',a).groups())
直接返回全部分组:('2017-10-30 11:12:34',)
😒 留下您对该文章的评价 😄