Python的re模块(Regular Expression正则表达式)提供各种正则表达式的匹配操作,和 Perl 脚本的正则表达式功能类似,使用这一内嵌于 Python 的语言工具,尽管不能满足所有复杂的匹配情况,但足够在绝大多数情况下能够有效地实现对复杂字符串的分析并提取出相关信息。
re模块
正则表达式使用反斜杠”\“来代表特殊形式或用作转义字符,这里跟python的语法冲突,因此用”\\“表示正则表达式中的”\“。为了使正则表达式具有更好的可读性,python设计了原始字符串(raw string),就是用’r’作为字符串前缀,如r”\n”:表示两个字符”\“和”n”,而不是换行符了。
1、re.findall(pattern, string[, flags])
方法能够以列表的形式返回匹配的子串。
1 | a = 'one1two2three3four4' |
基本语法可以参考菜鸟教程-python3正则表达式,或者直接查看python官方文档。下面再介绍几种常用的写法。注:content表示原始字符串,即需要提取的内容位于其中。
例一
“我院定于2017年12月15日9时30分,在本院第一法庭依法公开开庭审理上诉人王**与被上诉人广东**有限公司房屋买卖合同纠纷一案”
“本院定于2017年12月15日9时30分,在本院第一法庭依法公开开庭审理上诉人王**与被上诉人广东**有限公司房屋买卖合同纠纷一案”
有以上文段内容存在于多篇文章里,并且上述两种形式都有,提取以上文段内容的正则写法为:
1 | res = re.findall(r'([我本]院.*?一案)', content) |
解析:因为findall方法会匹配括号中的内容,以列表的形式返回匹配的子串,所以这里把整个需要匹配的文段内容都放在括号中,”[]”表示可以匹配其中的任意一项,”.”表示匹配除换行符之外的任意字符, “*”表示匹配0次或多次(与其类似的还有”+”,表示匹配1次或多次),”?”表示非贪婪匹配(即当从前往后匹配时遇到第一个满足条件的形式时就停止继续往后匹配,匹配的字符串长度尽可能地短)。
例二
“审理上诉人张三与被上诉人李四合同纠纷一案”
“审理原告张三与被告李四合同纠纷一案”
“审理申诉人张三与被申诉人李四合同纠纷一案”
“审理申请人张三与被申请人李四合同纠纷一案”
有以上文段内容存在于多篇文章中,并且上述几种形式不定,提取原告(这里为张三)的正则写法为:
1 | res = re.findall(r'(?:上诉人|原告|申诉人|申请人)(.*?)与', content) |
解析:例二与例一的不同之处在于”张三”之前的前缀字段的多种形式为非单个字符,无法使用”[]”进行匹配,只能使用”()”+”|”的形式来表示多种情况;而在括号的开头加上”?:”表示结果集中不匹配这个括号。
若不加res = [('上诉人', '张三')]
,
而这里res = ['张三']
。
例三
“2019-06-01”, “2019-06-1”, “2019-6-1”, “2019-6-01”
有以上日期格式,提取该格式的日期的正则写法为:
1 | res = re.findall(r'(\d{4}-\d{1,2})-\d{1,2}', content) |
解析:\d表示匹配数字,{n}表示匹配n次,{n,m}表示匹配n~m次,n若省略不写表示最少匹配0次,m若省略不写表示最多匹配无数次。
要注意的是python正则匹配时默认不匹配换行符的(.*?不会匹配换行符),如果字符串中存在换行符往往会匹配失败,所以在匹配前要先把换行符删掉,可以使用replace('\n', '')
或strip()
,前者可以去除所有位置的换行符,后者只能删除位于字符串两端的换行符以及各种空格。
但是如果确实需要匹配换行符时,可以采取re.findall(r'(.*?)', content, re.DOTALL)
或”[\s\S]*?”代替”.*?”。
此外,python正则还有诸如:匹配字符串的开头(^)、匹配字符串的结尾($)、匹配不在[]中的字符([^…])等功能以及\w,\s,\d(\W,\S,\D)等的巧妙用法。
其他
- ?除了非贪婪匹配,还有匹配0次或者1次的用法,当其前面是单个字符时;
- 如例一和例二所讲,当匹配单个字符有多种情况时可以使用
[我本]
,当匹配多个字符有多种情况时可以使用(?:上诉人|原告|申诉人|申请人)
,若在原来的逻辑上加上可为空的条件,后者可以直接写为(?:上诉人|原告|申诉人|申请人|)
,而前者不能写为[我本 ]
,可以使用后者的形式,如(?:我|本|)
,但是最优的方式应为:[我本]?
。 - 匹配中文:
[\u4e00-\u9fa5]
2、re.match和re.search
re.match(pattern, string, flags=0)
re.match尝试从字符串的起始位置开始匹配,若匹配成功返回一个匹配对象,否则返回None
re.match对象拥有以下方法:
start():返回匹配开始的位置
end():返回匹配结束的位置
span():返回一个元组包含匹配(开始,结束)的位置
下面重点讲group()和groups()方法的区别:
1 | import re |
解析:其中group(0)和group()效果相同,均为获取取得的字符串整体;
group(N)返回第N组括号匹配的字符(N>=1);
groups() 返回所有括号匹配的字符,以tuple格式:m.groups() == (m.group(1), m.group(2), …) 注意:这里是从group(1)开始的。
此外,还要注意一点,group()和group(0)并不强调匹配的过程中写括号,而group(N)和groups()只对括号起作用,比如下面的例子:
1 | import re |
上面的例子中在进行匹配时没有写括号,group()可以正常返回值,而group(1)却会报错,如果改成re.match('(a)', 'abc')
,group(1)便可以正常返回,并且groups()返回结果将为:(‘a’,)
re.search(pattern, string, flags=0)
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配。
3、re.finditer(pattern, string[. flags])
搜索string,返回一个顺序访问每一个匹配结果(Match对象)的迭代器。
1 | import re |
4、re.sub和re.subn
re.sub(pattern, repl, string, count=0, flags=0)
re.subn(pattern, repl, string, count=0, flags=0)
两种方法都是用来替换匹配成功的字串,值得一提的时,sub不仅仅可以是字符串,也可以是函数。subn函数返回元组,看下面例子。
1 | import re |
5、re.split(pattern, string, maxsplit=0)
split 方法按照能够匹配的子串将字符串分割后返回列表,它的使用形式如下:
1 | import re |
6、re.compile(strPattern[, flag])
compile 函数用于编译正则表达式,生成一个正则表达式( Pattern )对象,供 match()、search()和findall()等函数使用。
1 | import re |
That’s all. Thank you for reading.