本文系统记录了正则表达式的学习笔记
1 库与函数篇首先详细介绍的python正则表达式的库re:
match & search & findallimport 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 匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ fnrtv] # S 匹配任何非空白字符。等价于 [^ fnrtv]。 # 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'bbcb', s) #返回['bc'] ,匹配一个单独的单词 ‘bc’,而当它是其它单词的一部分的时候不匹配 re.findall(r'sbcs', s ) #返回[' bc '],配出的字符串中会包含那个分界符。 re.findall( r'Bbcw+', 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'bd{3}b', s) #返回三位数的数字['333']
re.findall( r'bd{2,4}b', s ) #返回2-4位的数字['22', '333', '4444']
re.findall( r'bd{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是一个合法的标识符 re.search(r'(and )(?P script)',s).group('sp') #返回'script',命名以后就可以用名字来进行索引 #使用compile对象可以查询分组索引 aa=re.compile(r'(and )(?P 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/b[a-z]+/b)|(?P /b/d+/b)|(?P /b[a-z_]+/w*/b)', re.I ) p.flags #返回2 p.pattern #返回'(?P //b[a-z]+//b)|(?P //b//d+//b)|(?P //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 、g 引用分组 m1.expand(r'name is /g<1> , age is /g , tel is /3') #返回'name is Tom , age is 24 , tel is 88888888'



