一、 前言
正则表达式在文本模式匹配的过程中, 是非常强大也是非常常用的工具
本文将简要介绍: 在Python中如何使用正则表达式进行匹配, 关于正则表达式的数学知识不再赘述
在正篇开始之前, 不要忘记字符串有原生的一些匹配函数, 如str.find()
、str.endwith()
、str.endwith()
, 有时我们并不需要正则表达式那么强大的功能—-我们应该尽量选用轻量级的实现以减少开销
二、 正篇
导入模块:
1
import re
2.1 match()
match()有两种用法, 但无论哪种方法, 都实现一个功能: 在字符串开头匹配一次正则表达式
举几个例子, 对于\d+/\d+/
这样的正则表达式, 有以下情况:
1
2
3
4
123/456/ -> 成功, 匹配到'123/456'
123/456/ajxo -> 成功, 匹配到'123/456'
123/456/789/234 -> 成功, 匹配到'123/456'
/123/456/ -> 失败, 在开头处匹配失败
下面是match()的两种用法:
2.1.1 传入两个字符串直接匹配
这种方法的形式是re.match(regular_expression:str, source:str) -> bool
查看示例:
1
2
3
4
5
6
7
8
9
10
11
12
import re
regx = r'\d+/\d+/'
string = '123/456/34'
if re.match(regx, string):
result = 'matched'
else:
result = 'not matched'
print(result)
注意: 正则表达式的字符串包含转义符, 使用时务必注意转义, 如在字符串前加’r’
2.1.2 预编译正则表达式后匹配
这种方法先使用re.compile()
对正则表达式进行编译, 生成一个对应的模式对象, 再使用这个模式对象进行匹配
查看示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
import re
regx = re.compile(r'\d+/\d+/')
string = '123/456/34'
print(type(regx))
if regx.match(string):
result = 'matched'
else:
result = 'not matched'
print(result)
2.1.3 match()的返回值
实践出真知:
1
print(type(re.match(regx, string)))
- 匹配成功时, 返回
<class '_sre.SRE_Match'>
- 匹配失败时, 返回
<class 'NoneType'>
直接打印这个对象试试:
1
2
3
match_ret = match(regx, string)
print(match_ret)
得到的结果是
1
<_sre.SRE_Match object; span=(0, 8), match='123/456/'>
可以看到核心的两个成员变量是span
和match
span
是匹配到的范围match
是匹配到的字符串
我们可以用其span()
方法得到span
、 访问string
以得到match:
1
2
print(match_ret.span())
print(match_ret.string)
得到的结果是:
1
2
(0, 8)
123/456/34
2.2 findall()
可以说是match()
的加强版, 它的作用是找出字符串中所有的匹配
注意: 在findall()下, 一个子串不能同时在两个个匹配结果中:
1
2
string = '123/456/34/2/1'
match_ret = regx.findall(string)
这样得到的匹配结果只有两个:'123/456/'
和'34/2/'
findall()
与match()
的返回值大有不同—-findall()
将匹配结果以列表的形式返回
承接上文的例子, 输出返回值, 结果为
1
['123/456/', '34/2/']
如果匹配失败, 则返回空列表, 由于空列表在条件语句中可以当做False使用, 所以findall()
也可以很便利地用于条件语句
2.3 捕获组
使用括号进行正则表达式匹配的分组, 也是python的前辈—-java的传统艺能了
我们使用括号, 对正则表达式的个别部分进行”标志”, 以在匹配完毕后使用group()
捕获这些特定的部分
2.3.1 match()
捕获组
对于match()
, 我们需要通过返回值的group()
方法捕获
查看示例:
1
2
3
4
5
6
7
8
9
10
import re
regx = re.compile(r'(\d+)/(\d+)/')
string = '123/456/'
match_ret = regx.match(string)
print(match_ret.group(0))
print(match_ret.group(1))
print(match_ret.group(2))
结果为:
1
2
3
123/456/
123
456
注意: group(0)返回的是整体的匹配结果, 这可能与我们的猜想不一样
2.3.2 findall()
捕获组
对于findall()
, 在分组匹配后, 其返回值发生了变化: 列表中的元素变为字符串的元组
查看示例:
1
2
3
4
5
6
7
8
9
import re
regx = re.compile(r'(\d+)/(\d+)/')
string = '123/456/789/321/'
match_ret = regx.findall(string)
print(match_ret)
结果为:
1
[('123', '456'), ('789', '321')]
把字符串变为元组的目的, 就是为了体现分组的效果
2.4 Python支持的正则表达式元字符和语法
数量词的贪婪模式与非贪婪模式
正则表达式通常用于在文本中查找匹配的字符串。Python里数量词默认是贪婪的(在少数语言里也可能是默认非贪婪),总是尝试匹配尽可能多的字符;非贪婪的则相反,总是尝试匹配尽可能少的字符。例如:正则表达式”ab*“如果用于查找”abbbc”,将找到”abbb”。而如果使用非贪婪的数量词”ab*?”,将找到”a”。
三、 参考资料
- David Beazley & Brian K.Jones - Python Cookbook (3rd edition)
- AstralWind - Python正则表达式指南