1.什么是re
正则表达式一门相对通用的语言,在python中也有对正则表达式的支持,那就是的内置re模块。正则表达式就是一系列的规则去匹配字符串然后进行相应的操作,这些规则网上一搜一大片,而re则是运用正则表达式来提供一系列的功能强大的接口让我们来调用。通常我们在对日志文件进行操作的时候会对正则表达式运用的比较多来得到我们希望得到的数据。
2.python中的转义符
正则表达式中通常用反斜杠'\'来代表转义,'\d'代表数字等,但是python本身也是通过反斜杠'\'来表示转义,所以就和正则表达式中的相冲突了,所以在python的re中两个反斜杠才能表示正则表达式中的一个,我们在正则表达式中要匹配一个反斜杠字符的时候就必须要写两个反斜杠,所以如果我们要匹配一个反斜杠那么就必须在re中写四个反斜杠,这是一个相当麻烦且容易出错的地方。
python中提供了原始字符串raw,一个以r开头的字符串表示这个是原始字符串,它就不会对特殊字符进行解析,比如反斜杠'\'就表示一个字符而不是转义符。所以在re中我们经常使用这种原始字符串。
3.re的使用
python通过re模块提供对正则表达式的支持,使用re模块一般是先将正则表达式的字符串形式编译成Pattern对象,然后用Pattern对象来处理文本得到一个匹配的结果,也就是一个Match对象,最后通过Match得到我们的信息并进行操作。
[learnpython@localhost learn]$ python Python 2.6.6 (r266:84292, Jan 22 2014, 09:42:36) [GCC 4.4.7 20120313 (Red Hat 4.4.7-4)] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import re >>> help(re.compile) Help on function compile in module re: compile(pattern, flags=0) Compile a regular expression pattern, returning a pattern object. (END)
通过help可以看到compile方法的介绍,返回一个pattern对象,但是却没有对第二个参数flags进行介绍。第二个参数flags是匹配模式,可以使用按位或'|'表示同时生效,也可以在正则表达式字符串中指定。Pattern对象是不能直接实例化的,只能通过compile方法得到。匹配模式有:
1).re.I(re.IGNORECASE): 忽略大小写
2).re.M(MULTILINE): 多行模式,改变'^'和'$'的行为
3).re.S(DOTALL): 点任意匹配模式,改变'.'的行为
4).re.L(LOCALE): 使预定字符类 \w \W \b \B \s \S 取决于当前区域设定
5).re.U(UNICODE): 使预定字符类 \w \W \b \B \s \S \d \D 取决于unicode定义的字符属性
6).re.X(VERBOSE): 详细模式。这个模式下正则表达式可以是多行,忽略空白字符,并可以加入注释
也可以直接将正则表达式字符串当做参数传进方法,就不用写一行compile代码,这样其实还是会将其编译成Pattern对象再匹配。
import re pattern = re.compile(r're') pattern.match('This is re module of python') re.compile(r're', 'This is re module of python') # 以上两种方式是一样的 # 以下两种方式是一样的 pattern1 = re.compile(r"""\d + #整数部分 \. #小数点 \d * #小数部分""", re.X) pattern2 = re.compile(r'\d+\.\d*')
match方法:
>>> help(re.match) Help on function match in module re: match(pattern, string, flags=0) Try to apply the pattern at the start of the string, returning a match object, or None if no match was found. (END) >>> match = re.match(r'This', 'This is re module of python') >>> print match <_sre.SRE_Match object at 0x7f0d047d1988> >>> print match.group() This >>> match = re.match(r'python', 'This is re module of python') >>> print match None
match方法是对字符串的开头进行匹配,如果匹配到则返回一个Match对象,如果匹配失败,则返回None,这个flags是编译pattern时指定的模式。group是Match对象的方法,表示得到的某个组的匹配,如果使用分组来查找字符串的各个部分,就可以通过group得到每个组匹配到的字符串。不写数字就是第0组,表示与整个表达式匹配的字符串,如果要得到第1组则是match.group(1),第二组是match.group(2)...
search方法:
>>> help(re.search) Help on function search in module re: search(pattern, string, flags=0) Scan through string looking for a match to the pattern, returning a match object, or None if no match was found. (END) >>> match = re.search(r'(\bt\w+)\W+(\w+)', 'This is test for python group') >>> print match <_sre.SRE_Match object at 0x23f62d8> >>> print match.group() test for >>> print match.group(0) test for >>> print match.group(1) test >>> print match.group(2) for
search()方法是在整个字符串中找,而match只是在字符串的开头找,上面匹配了两组字符串,即两个小括号里面的内容,所以如果写match.group(3)就是报错,不存在该组。如果给分组添加别名的话,就可以用到groupdict(),使用方法如下:
>>> match = re.search(r'(?P<first>\bt\w+)\W+(?P<second>\w+)', 'This is test for python group') >>> print match <_sre.SRE_Match object at 0x23f6250> >>> print match.group() test for >>> print match.group(0) test for >>> print match.group(1) test >>> print match.group(2) for >>> print match.groupdict() {'second': 'for', 'first': 'test'} >>> print match.groupdict()['first'] test >>> print match.groupdict()['second'] for
split方法:
>>> help(re.split) Help on function split in module re: split(pattern, string, maxsplit=0) Split the source string by the occurrences of the pattern, returning a list containing the resulting substrings. (END) >>> results = re.split(r'\d+', 'shdf23jdhf8jasdhf3hjd90') >>> type(results) <type 'list'> >>> print results ['shdf', 'jdhf', 'jasdhf', 'hjd', '']
按匹配到的字符串来分隔给定的字符串,然后返回一个列表list,maxsplit参数为最大的分隔次数。
findall方法:
>>> help(re.findall) Help on function findall in module re: findall(pattern, string, flags=0) Return a list of all non-overlapping matches in the string. If one or more groups are present in the pattern, return a list of groups; this will be a list of tuples if the pattern has more than one group. Empty matches are included in the result. (END) >>> results = re.findall(r'\bt\w+\W+\w+', 'this is test for python findall') >>> results ['this is', 'test for'] >>> results = re.findall(r'(\bt\w+)\W+(\w+)', 'this is test for python findall') >>> results [('this', 'is'), ('test', 'for')]
findall()方法返回的是一个列表,里面放的是所有匹配到的字符串,如果我们的正则表达式中没有给他们进行分组,那么就是匹配到的字符串,如果进行了分组,那么就是以元组的方式放在列表中。
finditer方法:
>>> help(re.finditer) Help on function finditer in module re: finditer(pattern, string, flags=0) Return an iterator over all non-overlapping matches in the string. For each match, the iterator returns a match object. Empty matches are included in the result. (END) >>> results = re.finditer(r'(\bt\w+)\W+(\w+)', 'this is test for python finditer') >>> type(results) <type 'callable-iterator'> >>> for it in results: ... print 'type:', type(it), ', it:', it, ', data:', it.group() ... type: <type '_sre.SRE_Match'> , it: <_sre.SRE_Match object at 0x220e250> , data: this is type: <type '_sre.SRE_Match'> , it: <_sre.SRE_Match object at 0x220e2d8> , data: test for
返回一个顺序访问每一个匹配结果Match对象的迭代器,通过上面代码type(it)可以看出是一个Match对象,然后通过Match对象的group方法得到匹配到的字符串。
sub方法:
>>> help(re.sub) Help on function sub in module re: sub(pattern, repl, string, count=0) Return the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in string by the replacement repl. repl can be either a string or a callable; if a string, backslash escapes in it are processed. If it is a callable, it's passed the match object and must return a replacement string to be used. (END) >>> print re.sub(r'(\w+) (\w+)', r'\2 \1', 'i say, hello world!') say i, world hello! >>> def func(m): ... print 'm:', m, ', first:', m.group(1).title(), ', second:', m.group(2).title() ... return m.group(1).title() + ' ' + m.group(2).title() ... >>> print re.sub(r'(\w+) (\w+)', func, 'i say, hello world!') m: <_sre.SRE_Match object at 0x220e250> , first: I , second: Say m: <_sre.SRE_Match object at 0x220e250> , first: Hello , second: World I Say, Hello World!
先通过正则表达式匹配string中的字符串,匹配到了再用repl来替换,count表示要替换的次数,不传参表示全部替换,返回的是替换过后的字符串。repl可以是一个字符串,也可以是一个方法,是方法的时候,必须有一个参数就是Match对象,必须返回一个用于替换的字符串。通过上面的代码可以看出,这个Match对象就是匹配到的Match对象,还记得match和search方法的返回值吧。如果要对匹配到的字符串做改变,用第二种方式会清晰一点。
subn方法:
>>> help(re.subn) Help on function subn in module re: subn(pattern, repl, string, count=0) Return a 2-tuple containing (new_string, number). new_string is the string obtained by replacing the leftmost non-overlapping occurrences of the pattern in the source string by the replacement repl. number is the number of substitutions that were made. repl can be either a string or a callable; if a string, backslash escapes in it are processed. If it is a callable, it's passed the match object and must return a replacement string to be used. (END) >>> print re.subn(r'(\w+) (\w+)', r'\2 \1', 'i say, hello world!') ('say i, world hello!', 2) >>> print re.subn(r'(\w+) (\w+)', r'\2 \1', 'i say, hello world!', count=1) ('say i, hello world!', 1)
subn方法和sub方法基本上是一样的,只是sub返回的是替换后的字符串,而subn返回的是一个元组,这个元组有两个元素,第一个是替换过后的字符串,第二个是number,也就是替换的次数,如果我们后面指定替换的次数后,那么这个number就和我们指定的count一样。
4.match(),search()和findall的区别
match()和search()区别就是match只是从字符串的开头匹配,如果开头没匹配到就返回None,匹配到了就返回一个Match对象,我们可以通过这个Match对象的group()方法得到匹配到的字符串。而search是从开头往后找,如果匹配到了就返回一个Match对象,如果没匹配到就返回None。
search()和findall()区别就是search只要匹配到一个就立刻返回一个Match对象,而不会匹配多个,如果没匹配到就返回None。findall就会从头到尾一直匹配到最后一个字符,返回一个列表,如果匹配到字符串就放在这个列表中,如果没有那么这个列表就是一个空列表。
# match和search >>> match = re.match(r'(\bt\w+)\W+(\w+)', 'This is test for python match') >>> type(match) <type 'NoneType'> >>> match = re.search(r'(\bt\w+)\W+(\w+)', 'This is test for python match') >>> print match.group() test for # search和findall >>> match = re.search(r'(\bt\w+)\W+(\w+)', 'this is test for python search') >>> print match.group() this is >>> match = re.findall(r'(\bt\w+)\W+(\w+)', 'this is test for python search') >>> print match [('this', 'is'), ('test', 'for')]
以上只是部分re模块的使用介绍,掌握这些操作后其他的基本都不是什么问题了。这里分享一篇介绍search和findall比较详细的文章:http://www.crifan.com/python_re_search_vs_re_findall/