# -*- coding: utf-8 -*-import reimport os#------------------------------------- re(正则表达式)模块 --------------------------------#-----------------------------------------------------------------------------------------------------#------------------------------------- 概念 --------------------------------#-----------------------------------------------------------------------------------------------------'''正则表达式:又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式使用单个字符串来描述、匹配一系列符合某个句法规则的字符串。在很多文本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。Python通过re模块提供对正则表达式的支持。使用re的一般步骤是先使用re.compile()函数,将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得匹配结果(一个Match实例),最后使用Match实例获得信息,进行其他的操作。'''#-----------------------------------------------------------------------------------------------------#------------------------------------- 元字符 --------------------------------#-----------------------------------------------------------------------------------------------------'''元字符(Meta-Characters)是正则表达式中具有特殊意义的专用字符,用来规定其前导字符(即位于元字符前面的字符)在目标对象中的出现模式。. 表示任意字符[] 用来匹配一个指定的字符类别,所谓的字符类别就是你想匹配的一个字符集,对于字符集中的字符可以理解成或的关系。^ 如果放在字符串的开头,则表示取非的意思。[^5]表示除了5之外的其他字符。而如果^不在字符串的开头,则表示它本身。\ 可以看成转意字符(同C语言)| 表示或 左右表达式各任意匹配一个,从左边先匹配起,如果成功,则跳过右边的表达式.如果没有放在()中,则范围是整个表达式具有重复功能的元字符* 对于前一个字符重复"0~无穷"次+ 对于前一个字符,重复"1~无穷"次? 对于前一个字符,重复"0~1"次{m,n} 对于前一个字符,重复"m~n"次,其中{0,}等价于*, {1,}等价于+, {0,1}等价于?{m,n}? 对前一个字符,重复"m~n"次,非贪婪模式{m} 对前一个字符,重复"m"次\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_]\A 匹配字符串的开头\Z 匹配字符串的结尾以下是(?...)系列 这是一个表达式的扩展符号。'?'后的第一个字母决定了整个表达式的语法和含义,除了(?P...)以外,表达式不会产生一个新的组。(?iLmsux) 'i'、'L'、'm'、's'、'u'、'x'里的一个或多个字母。表达式不匹配任何字符,但是指定相应的标志:re.I(忽略大小写)、re.L(依赖locale)、re.M(多行模式)、re.S(.匹配所有字符)、re.U(依赖Unicode)、re.X(详细模式)。(?P
...) 除了原有的编号外再额外指定一个别名(?P=name...) 引用别名name分组找到的字符串(?#...) #后面的将被作为注释, 相当于表达式中的注释(?:...) 匹配内部的RE所匹配的内容,但是不建立组。(?=...) 如果 ... 匹配接下来的字符,才算匹配,但是并不会消耗任何被匹配的字符,这个叫做“前瞻断言”。(?!...) 如果 ... 不匹配接下来的字符,才算匹配, 和(?=...)相反(?<=...) 只有当当前位置之前的字符串匹配 ... ,整个匹配才有效,这叫“后顾断言”。(?
...) -----------------"""(?P
...) 除了原有的编号外再额外指定一个别名"""m = re.match("(?P
\w+) (?P
\w+)", "hello world")  #匹配到第1个起别名'first',匹配到第2个起别名secondg = m.groupdict()print(g)#{'second': 'world', 'first': 'hello'}print(g['first'])#hello#-------------------- \number -----------------"""\number 引用编号为number的分组找到的字符串"""m = re.findall('(\d)he(\d)llo(\d)', '1he5llo2 3world4, 1he5llo5 3world4')print(m)#[('1', '5', '2'), ('1', '5', '5')]m = re.findall('\dhe\dllo\2', '1he5llo2 3world4, 1he5llo5 3world4')print(m)#[]#-------------------- (?iLmsux) -----------------"""'i'、'L'、'm'、's'、'u'、'x'里的一个或多个字母。表达式不匹配任何字符,但是指定相应的标志:re.I(忽略大小写)、re.L(依赖locale)、re.M(多行模式)、re.S(.匹配所有字符)、re.U(依赖Unicode)、re.X(详细模式)。"""s = 'hello foo1\nworld foo2\n'm = re.findall('foo.$', s)print(m)#['foo2']m = re.findall('(?m)foo.$', s)  #等价于m = re.findall('foo.$', s, re.M)print(m)#['foo1', 'foo2']s1 = 'HELLO WORLD'm = re.findall('(?i)[a-z]', s1)  #等价于m = re.findall('[a-z]', s, re.)print(m)#['H', 'E', 'L', 'L', 'O', 'W', 'O', 'R', 'L', 'D']#-------------------- (?P=name...) -----------------"""(?P=name...) 引用别名name分组找到的字符串"""#匹配到第1个起别名'first'+空格+匹配到第2个起别名second+逗号+别名first找到的结果作为搜索表达式的一部分m = re.match("(?P
\w+) (?P
\w+),(?P=first)", "hello world,hello world")g = m.groupdict()print(g)#{'second': 'world', 'first': 'hello'}m = re.match("(?P
\w+) (?P
\w+) (?P
(?P=first))", "hello world hello world")g = m.groupdict()print(g)#{'second': 'world', 'third': 'hello', 'first': 'hello'}#-------------------- (?#...) -----------------"""(?#...) #后面的将被作为注释, 相当于表达式中的注释"""s = 'hello1 #12345'm = re.findall('he\w+\d', s)print(m)#['hello1']m = re.findall('he\w+(?#前面这个表达式he\w+意思是he和任意单词字符的组合)\d', s)print(m)#['hello1']#-------------------- (?=...) -----------------"""(?=...) 如果 ... 匹配接下来的字符,才算匹配,但是并不会消耗任何被匹配的字符。例如 Isaac (?=Asimov) 只会匹配后面跟着 'Asimov' 的 'Isaac ',这个叫做“前瞻断言”。"""s = 'hellooookl world, help'g = re.findall('hel', s)print(g)#['hel', 'hel']g = re.findall('hel(?=lo)', s)  #遍历查找hel, (?=lo)位置跟着lo的才算print(g)#['hel']#-------------------- (?!...) -----------------"""(?!...) 和 (?!=...)正好相反。"""s = 'hello world, help'g = re.findall('hel(?!lo)', s)  #遍历查找hel, (?=lo)位置没有跟着lo的才算print(g)#['hel']g = re.findall('hel(?!klo)', s)  #遍历查找hel, (?=klo)位置没有跟着klo的才算print(g)#['hel', 'hel']#-------------------- (?<=...) -----------------"""(?<=...) 只有当当前位置之前的字符串匹配 ... ,整个匹配才有效,这叫“后顾断言”。"""s = 'hhello world, hkelp'g = re.findall('el', s)  #遍历查找elprint(g)#['el', 'el']g = re.findall('(?<=h)el', s)  #遍历查找el, (?<=h)位置跟着h的才算print(g)#['el']#-------------------- (?
、\g
引用分组,但不能使用编号0。\id与\g
是等价的;但\10将被认为是第10个分组,如果你想表达\1之后是字符'0',只能使用\g<1>0。"""match = re.match(r'(\w+) (\w+)(?P
.*)', 'hello world!')print(match.string)#hello world!print(match.re)#<_sre.SRE_Pattern object at 0x100298e90>print(match.pos)#0print(match.endpos)#12print(match.lastindex)#3print(match.lastgroup)#signprint(match.groups())#('hello', 'world', '!')print(match.group(0))#hello world!print(match.group(1, 2))#('hello', 'world')print(match.groupdict())#{'sign': '!'}print(match.start(2))#6print(match.end(2))#11print(match.span(2))#(6, 11)print(match.expand(r'\2 \1\3'))#world hello!#-------------------- re.search(pattern, string, flags=0) -----------------"""search对象是一次匹配的结果属性和方法同re.match(pattern, string, flags=0),它俩的区别:match()函数只检测RE是不是在string的开始位置匹配,search()会扫描整个string查找匹配;也就是说match()只有在0位置匹配成功的话才有返回,如果不是开始位置匹配成功的话,match()就返回none。"""s = 'hello world, hellp'print(re.match('hel', s).span())#(0, 3)print(re.match('ell', s))#Noneprint(re.search('hel', s).span())#(0, 3)print(re.search('ell', s).span())#(1, 4)#-------------------- Pattern相关实例方法 -----------------"""Pattern对象是一个编译好的正则表达式,通过Pattern提供的一系列方法可以对文本进行匹配查找。Pattern不能直接实例化,必须使用re.compile()进行构造。Pattern提供了几个可读属性用于获取表达式的相关信息:pattern: 编译时用的表达式字符串。flags: 编译时用的匹配模式。数字形式。groups: 表达式中分组的数量。groupindex: 以表达式中有别名的组的别名为键、以该组对应的编号为值的字典,没有别名的组不包含在内。"""p = re.compile(r'(\w+) (\w+)(?P
.*)', re.I)print(p.pattern)#(\w+) (\w+)(?P
.*)print(p.flags)#2print(p.groups)#3print(p.groupindex)#{'sign': 3}#-------------------- match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]) -----------------"""match(string[, pos[, endpos]]) | re.match(pattern, string[, flags]):这个方法将从string的pos下标处起尝试匹配pattern;如果pattern结束时仍可匹配,则返回一个Match对象;如果匹配过程中pattern无法匹配,或者匹配未结束就已到达endpos,则返回None。pos和endpos的默认值分别为0和len(string);re.match()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。注意:这个方法并不是完全匹配。当pattern结束时若string还有剩余字符,仍然视为成功。想要完全匹配,可以在表达式末尾加上边界匹配符'$'。"""s = 'hello world, help'p = re.compile('hel')m = p.match(s, 0, 10)print(m.group())#helm = p.match(s)print(m.group())#helm = re.match('hel', s)print(m.group())#hel#-------------------- search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]) -----------------"""2.search(string[, pos[, endpos]]) | re.search(pattern, string[, flags]):这个方法用于查找字符串中可以匹配成功的子串。从string的pos下标处起尝试匹配pattern,如果pattern结束时仍可匹配,则返回一个Match对象;若无法匹配,则将pos加1后重新尝试匹配;直到pos=endpos时仍无法匹配则返回None。pos和endpos的默认值分别为0和len(string));re.search()无法指定这两个参数,参数flags用于编译pattern时指定匹配模式。"""s = 'hello world, help'p = re.compile('hel')m = p.search(s, 0, 10)print(m.group())#helm = p.search(s)print(m.group())#helm = re.search('hel', s)print(m.group())#hel#-------------------- split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]) -----------------"""split(string[, maxsplit]) | re.split(pattern, string[, maxsplit]):按照能够匹配的子串将string分割后返回列表。maxsplit用于指定最大分割次数,不指定将全部分割。"""p = re.compile(r'\d+')print(p.split('one1two2three3four4'))#['one', 'two', 'three', 'four', '']print(p.split('one1two2three3four4', 2))#['one', 'two', 'three3four4']print(re.split(r'\d+','one1two2three3four4'))#['one', 'two', 'three', 'four', '']print(re.split(r'\d+', 'one1two2three3four4', 2))#['one', 'two', 'three3four4']#-------------------- findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]) -----------------"""findall(string[, pos[, endpos]]) | re.findall(pattern, string[, flags]):搜索string,以列表形式返回全部能匹配的子串。re中的findall无法指定字符串搜索起止位置, pattern中的findall无法指定标记类型"""p = re.compile(r'\d+')print(p.findall('one1two2three3four4'))#['1', '2', '3', '4']print(p.findall('one1two2three3four4', 10))#['3', '4']print(re.findall(r'\d+','one1two2three3four4'))#['1', '2', '3', '4']print(re.findall(r'\d+', 'one1two2three3four4', re.I))#['1', '2', '3', '4']#-------------------- finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]) -----------------"""finditer(string[, pos[, endpos]]) | re.finditer(pattern, string[, flags]):搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。re中的findall无法指定字符串搜索起止位置, pattern中的findall无法指定标记类型"""p = re.compile(r'\d+')for m in p.finditer('one1two2three3four4'):    print(m.group())#1#2#3#4for m in p.finditer('one1two2three3four4', 0, 10):    print(m.group())#1#2for m in re.finditer(p, 'one1two2three3four4'):    print(m.group())#1#2#3#4#-------------------- sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]) -----------------"""sub(repl, string[, count]) | re.sub(pattern, repl, string[, count]):使用repl替换string中每一个匹配的子串后返回替换后的字符串。当repl是一个字符串时,可以使用\id或\g
、\g
引用分组,但不能使用编号0。当repl是一个方法时,这个方法应当只接受一个参数(Match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。count用于指定最多替换次数,不指定时全部替换。"""p = re.compile(r'(\w+) (\w+)')s = 'i say, hello world!'m = re.search(p, s)print(p.sub(r'\2 \1', s))#say i, world hello!def func(x):    return x.group(1).title() + ' ' + x.group(2).title()print(p.sub(func, s))#I Say, Hello World!#-------------------- subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]) -----------------"""subn(repl, string[, count]) |re.sub(pattern, repl, string[, count]):返回 (sub(repl, string[, count]), 替换次数)"""p = re.compile(r'(\w+) (\w+)')s = 'i say, hello world!'m = re.search(p, s)print(p.subn(r'\2 \1', s))#('say i, world hello!', 2)def func(x):    return x.group(1).title() + ' ' + x.group(2).title()print(p.subn(func, s))#('I Say, Hello World!', 2)

在网上查阅引用了一些资料,顺带着的练习与总结,新手上路,不足之处多多指正