正则表达式学习笔记(python)
本文系统记录了正则表达式的学习笔记
1 库与函数篇
首先详细介绍的python正则表达式的库re:
match & search & findall
import re
re.match #从开始位置开始匹配,如果开头没有则返回None,顺利匹配则返回匹配值。
re.search #搜索整个字符串,返回符合匹配的值。只返回第一个满足条件的值。
re.findall #搜索整个字符串,返回符合匹配的一个list。返回所有满足条件的值,以列表形式呈现。
# r(raw)用在pattern之前,表示单引号中的字符串为原生字符,不会进行任何转义。
# 由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r'/t',等价于'//t')匹配相应的特殊字符。
re.match(r'l','liuyan1').group() #返回l
re.match(r'y','liuyan1') #返回None
re.search(r'y','liuyan1').group() #返回y
re.findall(r'yan','liuyan1') #返回['yan']
re.search(r'[^abc]','aeebdchdcbe').group() #非a、非b、非c的值。返回'e'
re.findall(r'[^abc]','aeebdchdcbe') #返回['e', 'e', 'd', 'h', 'd', 'e']
#I IGNORECASE 忽略大小写区别
#X VERBOSE 这个选项忽略规则表达式中的空白,并允许使用 ’#’ 来引导一个注释。
re.search(r'[a-z]+','liuyaN1234ab9').group() #返回'liuya'
re.search(r'[a-z]+','liuyaN1234ab9', re.I).group() #返回'liuyaN',对大小写不敏感
compile
re.compile #返回一个Pattern对象,这个pattern可以更便捷的使用上面的函数
s='111,222,aaa,bbb,ccc333,444ddd'
compiled_rule=re.compile(r'/b/d+/b')
compiled_rule.findall(s) #返回['111', '222']
rcm=re.compile(r'/d+',re.I)
# re 的 match 与 search 函数同 compile 过的 Pattern 对象的 match 与 search 函数的参数是不一样的。
# Pattern 对象的 match 、 search 、findall、finditer函数更为强大,是真正最常用的函数。他们比原来多了指定匹配开始位置和结束位置
#findall ( targetString , startPos ,endPos] )
#finditer ( targetString , startPos ,endPos )
#match ( targetString , startPos ,endPos )
#search ( targetString , startPos ,endPos)
finditer
re.finditer #返回一个迭代器.finditer 函数和 findall 函数的区别是, findall 返回所有匹配的字符串,并存为一个列表,而 finditer 则并不直接返回这些字符串,而是返回一个迭代器。
s='111 222 333 444'
for i in re.finditer(r'/d+',s):
print(i.group(),i.span())
## 返回:
# 111 (0, 3)
# 222 (4, 7)
# 333 (8, 11)
# 444 (12, 15)
sub & subn
re.sub #字符串的替换,返回替换后的字符串
re.subn #字符串的替换,返回替换后的字符串以及被替换的次数
s=' I have a dog , you have a dog , he have a dog '
re.sub( r'dog' , 'cat' , s )
#返回:' I have a cat , you have a cat , he have a cat '
s=' I have a dog , you have a dog , he have a dog '
re.sub( r'dog' , 'cat' , s , 2)
#返回:' I have a cat , you have a cat , he have a dog ' 只替换了前面两个
s=' I have a dog , you have a dog , he have a dog '
re.subn( r'dog' , 'cat' , s )
#返回:(' I have a cat , you have a cat , he have a cat ',3) 返回被替换的次数
split
re.split #切片函数。使用指定的正则规则在目标字符串中查找匹配的字符串,用它们作为分界,把字符串切片。
s=' I have a dog , you have a dog , he have a dog '
re.split( '/s*,/s*' , s )
#返回: [' I have a dog', 'you have a dog', 'he have a dog ']
2 模式字符串篇
2.1 基本规则
2.1.1 功能字符
# '|' 或规则 '|' 两边的字符串满足其中一个就可以返回
s = 'I have a dog , I have a cat'
re.findall( r'I have a dog|cat',s) #返回['I have a dog', 'cat']
# '.' 匹配所有字符串,除换行符'\n'。re.S可以让他包含换行符
s='123 \n456 \n789'
re.findall(r'.+',s) #返回['123 ', '456 ', '789']
re.findall(r'.+' , s , re.S) #返回['123 \n456 \n789']
#‘^’ 和 ’$’ 匹配字符串开头和结尾。注意 ’^’ 不能在‘ [ ] ’中,否则含意就发生变化。在多行模式下,它们可以匹配每一行的行首和行尾。
re.findall(r'^12' , s , re.S) #返回['12']
2.1.2 集合设定符
# [amk] 匹配 'a','m'或'k'。相当于a|m|k
# [^abc] 匹配除了a,b,c之外的字符
re.findall(r'[英雄]','英雄好汉英雄') #返回['英', '雄', '英', '雄']
re.findall(r'[^abc]','aeebdchdcbe') #返回['e', 'e', 'd', 'h', 'd', 'e']
#注意,^需要放在开头。 [a-z^A-Z] 表明的是匹配所有的英文字母和字符 ’^’
re.findall(r'[ab^c]','aeebd^^chdcbe') #返回['a', 'b', '^', '^', 'c', 'c', 'b']
#[0-9] 匹配任何数字。类似于 [0123456789]
#[a-z] 匹配任何小写字母
#[A-Z] 匹配任何大写字母
#[a-zA-Z0-9] 匹配任何字母及数字
2.1.3 预定义转义字符
# \d 匹配一个数字字符。等价于[0-9]
# \D 匹配一个非数字字符。等价于 [^0-9]。
# \s 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]
# \S 匹配任何非空白字符。等价于 [^ \f\n\r\t\v]。
# \w 匹配包括下划线的任何单词字符。等价于'[A-Za-z0-9_]'。
# \W 匹配任何非单词字符。等价于 '[^A-Za-z0-9_]'。
# \n 匹配一个换行符,
# \t 匹配一个制表符。
# \A 匹配字符串开头。它和 ’^’ 的区别是, ’/A’ 只匹配整个字符串的开头,即使在 ’M’ 模式下,它也不会匹配其它行的很首。 s= '12 34/n56 78/n90'
# \Z 匹配字符串的结尾。它和 ’$’ 的区别是, ’/Z’ 只匹配整个字符串的结尾,即使在 ’M’ 模式下,它也不会匹配其它各行的行尾。 s= '12 34/n56 78/n90'
# \b 匹配字符边界
# \B 匹配非边界的字符
s ='abc abcde bc bcd'
re.findall(r'\bbc\b', s) #返回['bc'] ,匹配一个单独的单词 ‘bc’,而当它是其它单词的一部分的时候不匹配
re.findall(r'\sbc\s', s ) #返回[' bc '],配出的字符串中会包含那个分界符。
re.findall( r'\Bbc\w+', s ) #返回['bcde'],匹配包含 ’bc’ 但不以 ’bc’ 为开头的单词。# 成功匹配了 ’abcde’ 中的 ’bcde’ ,而没有匹配 ’bcd’
2.2重复
2.2.1重复多次
#a* 匹配0个或多个的表达式a。
#a+ 匹配1个或多个的表达式a。
#a? 匹配0个或1个的表达式a。
re.findall(r'ab*','aababababbb') #返回['a', 'ab', 'ab', 'ab', 'abbb']
re.findall(r'ab+','aababababbb') #返回['ab', 'ab', 'ab', 'abbb']
re.findall(r'ab?','aababababbb') #返回['a', 'ab', 'ab', 'ab', 'ab']
2.2.2精确匹配和最小匹配
# '{m}' 精确匹配 m 次
# '{m,n}' 匹配最少 m 次,最多 n 次。 (n>m)
s = ' 1 22 333 4444 55555 666666 '
re.findall(r'\b\d{3}\b', s) #返回三位数的数字['333']
re.findall( r'\b\d{2,4}\b', s ) #返回2-4位的数字['22', '333', '4444']
re.findall( r'\b\d{5,}\b', s ) #返回5位及以上的数字['22', '333', '4444']
2.2.2精确匹配和最小匹配
#所谓惰性,就是返回满足条件的最小单元。
# '*?' 重复任意次匹配(0次和n次都可以),但返回的是最少重复的结果
s = 'acbabaccb'
re.findall( r'a.*b', s ) #返回['acbacbaccb'],此时返回a与b之间最多重复次数的那个匹配值
re.findall( r'a.*?b', s ) #返回['acb', 'ab', 'accb'],返回a与b之间最少重复次数的匹配值,一共匹配到三个(也就是a与b之间没有更小单位的可匹配值)
# '+?' 重复任意次匹配(1次和n次都可以),但返回的是最少重复的结果
re.findall( r'a.+?b', s ) #返回['acb','abaccb']
# '??' 重复0次或1次匹配,但返回的是最少重复的结果
re.findall( r'a.??b', s ) #返回['acb', 'ab']
# '{n,m}?' 重复n到m次,但尽可能少重复
re.findall( r'a.{1,2}?b', s ) #返回['acb', 'accb'],为什么不返回'abaccb',因为他超过限定长度
# '{n,}?' 重复n次以上,但尽可能少重复
re.findall( r'a.{1,}?b', s ) #返回['acb', 'abaccb'],为什么会返回'abaccb',因为他是符合条件的最小单元
2.3 组的概念与相关类
#分组就是用一对圆括号“()”括起来的正则表达式,匹配出的内容就表示一个分组,也有一种说法称为‘捕获’。
#从正则表达式的左边开始看,看到的第一个左括号“(”表示第一个分组,第二个表示第二个分组,依次类推.
# 需要注意的是,有一个隐含的全局分组(就是0),就是整个正则表达式。
s = "I love javascript and java and scriptscript"
re.search(r'and script',s).group(0) #返回'and script',这个常规查找一个字符串
#现在对他进行一个分组
re.search(r'(and )(script)',s).group(0) #返回'and script',第0组返回全局分组
re.search(r'(and )(script)',s).group(1) #返回'and ',返回第一个分组
re.search(r'(and )(script)',s).group(2) #返回'script',返回第二个分组
#分组以后可以对分组内容进行重复计算
re.search(r'(and )(script)+',s).group(0) #返回'and scriptscript',在全局分组中,响应了+
re.search(r'(and )(script)+',s).group(1) #返回'and ',返回第一个分组
re.search(r'(and )(script)+',s).group(2) #返回'script',返回第二个分组
#findall返回内容会有所不同,他先匹配出全局分组,然后从全局分组提取子分组展示出来
s = "I love javascript and scriptscript and scriptscript"
re.findall(r'(and )(script)+',s) #返回[('and ', 'script'), ('and ', 'script')],现在能匹配到两段,把两段都回传,并把其他子分组提取出来
# 有些时候分组太多,我们可以命名分组
# (?P<name>正则表达式) name是一个合法的标识符
re.search(r'(and )(?P<sp>script)',s).group('sp') #返回'script',命名以后就可以用名字来进行索引
#使用compile对象可以查询分组索引
aa=re.compile(r'(and )(?P<sp>script)')
aa.groupindex #返回mappingproxy({'sp': 2})
# 无捕获数组,我们希望匹配,但是无需捕获
# (?:exp) 匹配exp,不捕获匹配的文本
re.search(r'(and )(?:script)',s).group(0) #返回'and script'
re.search(r'(and )(?:script)',s).group(1) #返回'and '
re.search(r'(and )(?:script)',s).group(2) #报错无返回
re.findall(r'(and )(?:script)',s) #返回['and '],没有返回script
#当你只是希望利用分组来进行重复计数,但不需要返回指定分组的时候,可以使用无捕获数组,减少内存压力
re.search(r'and (?:script)+',s).group(0) #返回'and scriptscript'
# 编译指定选项组
# Python 的正则式可以指定一些选项,这个选项可以写在 findall 或 compile 的参数中,也可以写在正则式里,成为正则式的一部分。
# 编译选项 ’i’ 等价于 IGNORECASE ,L 等价于 LOCAL ,m 等价于 MULTILINE , s 等价于 DOTALL , u 等价于 UNICODE , x 等价于 VERBOSE
#(?imx: exp) 在括号中使用i, m, 或 x 可选标志,只影响组内
#(?-imx: re) 在括号中不使用i, m, 或 x 可选标志
# 注释组'(?# exp)' exp为注释内容
#Python 允许你在正则表达式中写入注释,在 (?#'exp') 之间的内容将被忽略
3 compile的拓展内容
#compile以后获得一个编译的pattern对象
#flags 查询编译时的选项
#pattern 查询编译时的规则
#groupindex 规则里的组
p = re.compile(r'(?P<word>/b[a-z]+/b)|(?P<num>/b/d+/b)|(?P<id>/b[a-z_]+/w*/b)', re.I )
p.flags #返回2
p.pattern #返回'(?P<word>//b[a-z]+//b)|(?P<num>//b//d+//b)|(?P<id>//b[a-z_]+//w*//b)'
p.groupindex #返回{'num': 2, 'word': 1, 'id': 3}
content='xshfjdshfks'
m1 = p.match(content,3)
m1.group() #返回匹配结果
m1.group(0) #返回匹配的全局分组
m1.groupdict() #返回以组名为 key ,匹配的内容为 values 的字典
m1.span() #返回匹配范围
m1.start() #返回开始下标
m1.end() #返回结束下标
m1.expand(template) #将匹配到的分组代入template中然后返回。template中可以使用\id或\g<id>、\g<name>引用分组
m1.expand(r'name is /g<1> , age is /g<age> , tel is /3') #返回'name is Tom , age is 24 , tel is 88888888'