简单介绍:
此模块儿常用来使用形式化模式搜索和修改文本,默认使用Perl的正则表达式语法为基础并提供了一些特定的与PYTHON的改进
正则表达:
. 匹配任意除\n之外的字符,在DOTALL模式中也能匹配换行符
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = '5\n2\n1' # 非re.S模式,此时.匹配除换行符之外的字符 match = re.match(r'5.2.1', sources_str) if match: print match.group() print '-------------------------------------' # 为re.S模式,此时.匹配含换行符之外的字符 match = re.match(r'5.2.1', sources_str, re.S) if match: print match.group() if __name__ == '__main__': main()
\ 转义字符,使后一个字符改变原有的意思,如果字符串中有字符*需要匹配则需\*或是字符集[*]
[] 匹配字符集合,可通过-表示范围,^表示取反,[A-Za-z0-9]则只匹配a-zA-Z0-9这个集合中的单个字
\d 匹配数字[0-9]
\D 匹配非数字[^\d]
\s 匹配空白字符[ \t\r\n\f\v]
\w 匹配单词字符[A-Za-z0-9_]
\W 匹配非单词字符[^\w]
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'LiManMan * phone number is 18814818764?' match = re.match(r'[a-zA-Z]+\s\*\s\w+\s\w+\s\w+\s\d+\W', sources_str) if match: print match.group() if __name__ == '__main__': main()
* 匹配一个字符0或多次
+ 匹配一个字符1次或是多次
? cha匹配一个字符0次或是1次
{m} 匹配一个字符m次
{m,n} 匹配一个字符最小m次,{m,}表示至少匹配m次,{,n}表示最多匹配n次
*? +? ?? {m,n}? 使* + ?? {m,n}变为非贪婪模式
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'LiManMan * phone number is 18814818764' # 贪婪模式 match = re.match(r'[a-zA-Z]{1,}\s[*]\s\w+\s\w+\s\w+\s\d+', sources_str) if match: print match.group() # 非贪婪模式 match = re.match(r'[a-zA-Z]{1,}\s[*]\s\w+\s\w+\s\w+\s\d+?', sources_str) if match: print match.group() if __name__ == '__main__': main()
^ 匹配字符串开头,多行模式中匹配每一行的开头
$ 匹配字符串末尾,多行模式中匹配每一行的末尾
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = '5\n2\n1' # ^匹配单行模式, $用法一样 match = re.findall(r'^\d', sources_str) if match: print match # ^匹配多行模式, $用法一样 match = re.finditer(r'^\d', sources_str, re.M) if match: # 遍历迭代对象 for cur_match in match: print cur_match.group() if __name__ == '__main__': main()
\A 必须出现在字符串的开头和^的区别在于多行模式下依然单行匹配
\Z 必须出现在字符串的结尾和$的区别在于多行模式下依然单行匹配
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = '5\n2\n1' # \A和\Z匹配时候其实忽略re.M多行特性,只会匹配整个sources_str match = re.findall(r'\A\d\Z', sources_str, re.M) if match: print match print '-----------------------------------------------------' # 单行匹配测试 match = re.findall(r'\A5\n2\n1\Z', sources_str, re.M) if match: print match if __name__ == '__main__': main()
\b 仅匹配单词的分割处,常见的分割如空格/标点/换行等
\B [^\b]
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'i#love#you!' # \b其实匹配的是任意字符分割符 match = re.search(r'\blove\b', sources_str) if match: print match.group() if __name__ == '__main__': main()
| 代表左右表达式任意匹配一个,总是线尝试匹配左边的表达式,一旦匹配成功则跳过匹配右边的表达式,如果|没有在()中则范围是整个表达式(因为|在正则表达式中有特殊含义所以要包含|的字符串必须\转义先)
() 表示表达式分组,从表达式左边开始每遇到一个分组的左括号,编号+1,另外分组表达式可以作为一个总体可以后接数量词
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'python linux oracle mysql' # ()和|结合使用可以同时匹配多个元素 match = re.findall(r'(python|linux|mysql)', sources_str) if match: print match if __name__ == '__main__': main()
(?iLmsux)iLmsux的每个字符代表一个匹配模式,只能用在正则表达式的开头,可选多个,匹配模式后面再说
(?P<name>pattern) 分组,除了原有的编号外再指定一个额外的别名
\<number> 引用编号为<number>的分组匹配到的字符串
(?:pattern) (...)的不分组版本,用于使用|或是后接数量词
(?#pattern) #后的内容将作为注释被忽略
(?=pattern) 之后的字符串需要匹配表达式后才能成功匹配,不消耗字符串内容
(?!pattern) 之后的字符串需要不匹配表达式才能成功匹配,不消耗字符串内容
(?<=pattern) 之前的字符串需要匹配表达式后才能成功匹配,不消耗字符串内容
(?<!pattern) 之前的字符串需要不匹配表达式才能成功匹配,不消耗字符串内容
(?(id/name)yes-pattern|no-pattern) 如果编号为id/别名为name的组匹配到字符,则需要匹配yes-pattern,否则需要匹配no-pattern
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'inet 172.24.10.1 netmask 255.255.255.0' # 只有match返回的对象才能分组 match = re.match(r'''inet \s+ (?P<ipaddr>[0-9.]+) \s+ netmask \s+ (?P<netmask>[0-9.]+)''', sources_str, re.X) if match: print match.groupdict() if __name__ == '__main__': main()
常用方法:
re.compile(pattern, flags=0) -> pattern
说明:将正则表达式字符串编译成pattern对象(生成缓存对象,避免缓存查找开销),第二个参数flags是匹配模式,取值可以使用按位“|”表示同时生效,re.compile(pattern, re.I|re.M)和re.compile((?im)pattern是等价的
re.I 忽略大小写
re.M 多行模式,改变^和$的行为
re.S 点任意匹配模式,改变.行为
re.L 使预定义\w\W\b\B\s\S取决于当前区域设定
re.U 使预定义\w\W\b\B\s\S取决于unicode定义的字符属性
re.X 详细模式,这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
pattern 编译时用的正则表达式字符串
re.match(pattern, string, flags=0) -> match
说明:将pattern编译后应用于字符串,只有当被搜索字符串的开头匹配模式的时候才能查到匹配对象,成功返回的matchobject包含很多匹配的信息,如果没有匹配成功则返回None
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'i love you.' # 编译正则表达式 pattern_obj = re.compile(r'''[a-z]\s # match i [a-z]+\s# match love [a-z]+. # match you.''', re.X) # 匹配正则表达式 match = re.match(pattern_obj, sources_str) if match: print match.group() if __name__ == '__main__': main()
re.search(pattern, string, flags=0) -> match
说明:将pattern编译后应用于字符串,只要找到任意位置匹配子串则停止继续查找,成功返回的matchobject包含很多匹配的信息,如果没有匹配成功则返回None
re.split(pattern, string, maxsplit=0) -> list
说明:按照能够匹配的子串将string切割后返回列表,maxsplit用于指定最大分割次数,不指定将全部分割
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re def main(): """Main function. """ sources_str = 'i love you' # re.split可以用任意正则表达式分割字符串,以及设置分割的次数 match = re.split(r'\s', sources_str, maxsplit=2) if match: print match if __name__ == '__main__': main()
re.findall(pattern, string, flags=0) -> list
说明:搜索string字符串,将以列表形式返回全部能匹配的子串
re.finditer(pattern, string, flags=0) -> iterator
说明:搜索string字符串,返回一个顺序访问每一个匹配结果(Matach)对象的迭代器
re.sub(pattern, repl, string, count=0) -> str
说明:使用repl替换string中的每一个匹配的子串后返回替换后的字符串,当repl是一个字符串时,可以使用\g<id>或\g<name>引起分组,但不能使用编号0,当repl是一个方法时,这个方法应当只接受一个参数(match对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组),count用于指定最多被替换多少次,不指定时全部替换
# -*- coding: utf-8 -*- """ # # Authors: limanman # OsChina: http://my.oschina.net/pydevops/ # Purpose: # """ import re import colorama def highlight(match): """High light search_strs. Args: match: re match object Returns: string """ colorama.init() return ''.join([colorama.Fore.RED, match.group(), colorama.Fore.RESET]) def main(): """Main function.""" # 定义搜索的文件 user_file = '/etc/passwd' # 此时文件偏移为0 with open(user_file, 'r+b') as rhandler: while True: search_strs = raw_input('please input search string: ').strip() if len(search_strs) == 0: continue if search_strs in ('quit', 'exit'): break for cur_line in rhandler: # 存在search_strs就高亮替换 if search_strs in cur_line: cur_line = re.sub(search_strs, highlight, cur_line) print cur_line, # 回到文件开头 rhandler.seek(0) if __name__ == '__main__': main()
pattern对象:
P.groups 表达式中分组的数量
P.groupindex 返回{分组键名,分组id}的字典,没有别名的分组不包含在内
match对象:
M.string 匹配时使用的文本
M.re 匹配时使用的pattern对象
M.pos 文本中正则表达式开始搜索的索引(默认是0)
M.endpos 文本中正则表达式结束搜索的索引(默认是文本的长度)
M.lastindex 最后一个被捕捉的分组在文本中的索引,如果没有被捕捉的分组则返回None
M.lastgroup 最后一个被捕捉的分组的别名,如果这个分组没有别名或者没有被捕获的分组则返回None
M.group([group1,...]) 获得一个或是多个分组字符串,参数可以有多个,group1可以是分组的别名或是id,默认参数不写或是group(0)则返回整个字符串,没有截获字符串的组返回None,截获了多次的组返回最后一次截获的子串
M.groups([default]) 以元组形式返回全部分组捕获的字符串,相当于调用group(1,2...last),default表示没有截获字符串的组时候返回此字符串,默认为None
M.groupdict([default]) 返回以别名的组的别名为键,以该组截获的字串为值的字典,没有别名的组不包含在内,default表示没有截获字符串的组时候返回此字符串,默认为None
M.start([group]) 返回指定的组截获的字串在string的起始索引(子串的第一个字符的索引),group默认的值为0
M.end([group]) 返回指定的组截取的子串在string中的结束索引(子串最后一个字符的索引+1),group默认为0
M.span([group]) 返回一个元组,(start(group), end(group))
M.expand(string_template) 将匹配到的分组代入Template模版中返回,Template中可以使用\g<id>,\g<name>引用分组