参考资料:
1.菜鸟教程-Python 3 正则表达式,网址:https://www.runoob.com/python3/python3-reg-expressions.html
2.《Python从小白到大牛》,作者关东升,清华大学出版社
3.《Python数据分析基础》,作者[美]Clinton W. Brownley,译者陈光欣,中国工信出版集团,人民邮电出版社
简述正则表达式
正则表达式(Regular Expression)是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配。在Python中,正则表达式的应用非常广泛,如数据挖掘、数据分析、网络爬虫、输入有效性验证等。
re模块使Python拥有全部的正则表达式功能。我们使用下面的语句来导入该模块:
import re
正则表达式字符串
正则表达式字符串由普通字符和元字符组成。
普通字符是按照字符字面意义表示的字符。元字符是预先定义好的一些特殊字符,如\w+
和\.
都属于元字符。
下面是一些基本元字符:
字符 | 说明 |
---|---|
\ | 转义符号 |
. | 表示任意一个字符 |
+ | 表示重复一次或多次 |
* | 表示重复零次或多次 |
? | 表示重复零次或一次 |
| | 选择符号,表示“或” |
{} | 定义量词 |
[] | 定义字符类 |
() | 定义分组 |
^ | 表示取反,或匹配一行的开始 |
$ | 匹配一行的结束 |
上面提到了元字符^
和$
,它们可以匹配一行字符串的开始和结束。当以^
开始时,要求一行字符串的开始位置匹配;当以$
位置结束时,要求一行字符串的结束位置匹配。需要注意的是,正则表达式\w+@qq\.com
和^\w+@qq\.com$
是不同的。
定义字符类需要使用元字符[]
。例如说我们想在输入的字符串中匹配Python或python,则可以使用正则表达式[Pp]ython
。
在正则表达式中指定不想出现的字符,可以在字符类之前加^
符号进行字符类取反。比如说,正则表达式[^0123456789]
表示输入的字符串中出现非0~9数字即匹配,也就是出现在[0123456789]
之外的任意字符即匹配。
上面所说的正则表达式[^0123456789]
写起来非常麻烦。事实上,我们引入区间的概念之后,这种连续的字符可以使用区间来表示。区间使用连字符-
表示。例如[0123456789]
可以采用区间表示为[0-9]
,[^0123456789]
可以采用区间表示为[^0-9]
。区间也可以表示连续的英文字母字符类,例如[a-z]
表示所有小写字符类,[A-Z]
表示所有大写字母字符类。除此之外,也可以表示多个不同区间,例如[A-Za-z0-9]
表示所有字母和数字字符类,[0-36-8]
表示0、1、2、3、6、7、8几个数字字符组成的字符类。
正则表达式提供了预定义字符类。预定义字符类如下表所示:
字符 | 说明 |
---|---|
. | 匹配任意一个字符 |
\\ | 匹配反斜杠\字符 |
\n | 匹配换行符 |
\r | 匹配回车符 |
\f | 匹配一个换页符 |
\t | 匹配一个水平制表符 |
\v | 匹配一个垂直制表符 |
\s | 匹配一个空格符(等价于[\t\n\r\f\v]) |
\S | 匹配一个非空格符(等价于[^\s]) |
\d | 匹配一个数字字符(等价于[0-9]) |
\D | 匹配一个非数字字符(等价于[^0-9]) |
\w | 匹配任何语言的单词字符(包括英文字母、亚洲文字等)、数字和下划线等字符,如果正则表达式编译标志设置为ASCII,则只匹配[a-zA-Z0-9_] |
\W | 等价于[^\w] |
量词
在正则表达式中,元字符只能匹配显示一次字符或字符串。如果想要匹配显示多次字符或字符串,可以使用量词。
正则表达式中的量词如下表所示:
字符 | 说明 |
---|---|
? | 出现零次或一次 |
* | 出现零次或多次 |
+ | 出现一次或多次 |
{n} | 出现n次 |
{n,m} | 至少出现n次但不超过m次 |
{n,} | 至少出现n次 |
下面是一个量词的使用示例代码:
import re
m = re.search(r'\d?', '87654321') # 出现数字一次
print(m) # 匹配字符'8'
m = re.search(r'\d?', 'ABC') # 出现数字零次
print(m) # 匹配字符''
m = re.search(r'\d*', '87654321') # 出现数字多次
print(m) # 匹配字符'87654321'
m = re.search(r'\d*', 'ABC') # 出现数字零次
print(m) # 匹配字符''
m = re.search(r'\d+', '87654321') # 出现数字多次
print(m) # 匹配字符'87654321'
m = re.search(r'\d+', 'ABC')
print(m) # 不匹配
m = re.search(r'\d{8}', '87654321') # 出现数字8次
print(m) # 匹配字符'87654321'
m = re.search(r'\d{8}', 'ABC')
print(m) # 不匹配
m = re.search(r'\d{7,8}', '87654321') # 出现数字8次
print(m) # 匹配字符'87654321'
m = re.search(r'\d{9,}', '87654321')
print(m) # 不匹配
输出结果如下:
<re.Match object; span=(0, 1), match='8'>
<re.Match object; span=(0, 0), match=''>
<re.Match object; span=(0, 8), match='87654321'>
<re.Match object; span=(0, 0), match=''>
<re.Match object; span=(0, 8), match='87654321'>
None
<re.Match object; span=(0, 8), match='87654321'>
None
<re.Match object; span=(0, 8), match='87654321'>
None
量词还可以细分为贪婪量词和懒惰量词。贪婪量词会尽可能多地匹配字符,懒惰量词会尽可能少地匹配字符。大多数计算机语言的正则表达式量词默认是贪婪量词,如果要使用懒惰量词,在量词之后加?
即可。
下面是一个示例代码:
import re
m = re.search(r'\d{5,8}', '87654321') # 出现数字8次
print(m) # 匹配字符'87654321'
m = re.search(r'\d{5,8}?', '87654321') # 出现数字5次
print(m) # 匹配字符'87654'
输出结果如下:
<re.Match object; span=(0, 8), match='87654321'>
<re.Match object; span=(0, 5), match='87654'>
分组
量词只能重复显示一个字符,如果想让一个字符串作为整体使用量词,可以将这个字符串放到()
中,这就是分组,也被称作子表达式。
下面是一个使用分组的示例代码:
import re
p = r'(121){2}'
m = re.search(p, '121121abcabc')
print(m) # 匹配
print(m.group()) # 返回匹配字符串
print(m.group(1)) # 获得第一组内容
p = r'(\d{3,4})-(\d{7,8})'
m = re.search(p, '010-87654321')
print(m) # 匹配
print(m.group()) # 返回匹配字符串
print(m.groups()) # 获得所有组内容
输出结果如下:
<re.Match object; span=(0, 6), match='121121'>
121121
121
<re.Match object; span=(0, 12), match='010-87654321'>
010-87654321
('010', '87654321')
在Python中访问分组时,除了可以通过组编号访问,还可以通过组名访问。这需要我们在正则表达式中为组命名。组命名通过在组开头添加?P<分组名>
实现。
在正则表达式中,反向引用语法是\组编号
。组编号从1开始。
前面所说的分组称为捕获分组。捕获分组的子表达式结果被暂时保存到内存中,以备表达式或其他程序通过组编号或组名进行引用。但是有时,我们并不想引用子表达式的匹配结果,不想捕获匹配结果,只是将小括号作为一个整体进行匹配。这个时候我们就可以使用非捕获分组。在组开头使用?:
可以实现非捕获分组。
Python的re模块
re.search()函数
re.search()函数在输入字符串中查找,返回第一个匹配内容,如果找到一个则match对象,如果没有找到则返回None。
函数语法如下:
re.search(pattern, string, flags=0)
参数说明如下:
参数 | 参数说明 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等 |
re.match()函数
re.match()函数在输入字符串开始处查找匹配内容,如果找到一个则match对象,如果没有找到则返回None。
函数语法如下:
re.match(pattern, string, flags=0)
参数说明如下:
参数 | 参数说明 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等 |
下面我们简单讨论一下re.search()和re.match()的区别。
re.match()只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;re.search()匹配整个字符串,直到找到一个匹配。
re.search()和re.match()如果匹配成功都返回match对象。下面是match对象的一些常用方法:
方法 | 返回值 |
---|---|
group() | 返回匹配的子字符串 |
start() | 返回子字符串的开始索引 |
end() | 返回子字符串的结束索引 |
span() | 返回子字符串的跨度,它是一个二元素的元组 |
re.findall()函数
re.findall()函数在输入字符串中查找所有匹配内容,如果匹配成功,则返回match列表对象,如果匹配失败则返回None。
函数语法如下:
re.findall(string[, pos[, endpos]])
参数说明如下:
参数 | 参数说明 |
---|---|
string | 待匹配的字符串 |
pos | 可选参数,指定字符串的起始位置,默认为0 |
endpos | 可选参数,指定字符串的结束为止,默认为字符串的长度 |
re.finditer()函数
re.finditer()函数在输入字符串中查找所有匹配内容,如果匹配成功,则返回容纳match的可迭代对象,通过迭代对象每次可以返回一个match对象,如果匹配失败则返回None。
函数语法如下:
re.finditer(pattern, string, flags=0)
参数说明如下:
参数 | 参数说明 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等 |
re.split()函数
re.split()函数按照匹配的字符串进行字符串分割,返回字符串列表对象。
函数语法如下:
re.split(pattern, string[, maxsplit=0, flags=0])
参数说明如下:
参数 | 参数说明 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
maxsplit | 分割次数,默认为0,不限制次数 |
flags | 标志位,用于控制正则表达式的匹配方式,如是否区分大小写,多行匹配等 |
re.sub()函数
re.sub()函数用于替换匹配的子字符串,返回替换之后的字符串。
函数语法如下:
re.sub(pattern, repl, string, count=0, flags=0)
参数说明如下:
参数 | 参数说明 |
---|---|
patern | 正则中的模式字符串 |
repl | 替换的字符串,也可为一个函数 |
string | 要被查找替换的原始字符串 |
count | 模式匹配后替换的最大次数,默认为0,表示替换所有的匹配 |
flags | 编译时用的匹配模式,数字形式 |
re.compile()函数
re.compile()函数可以编译正则表达式。
函数语法如下:
re.compile(pattern[, flags=0])
参数说明如下:
参数 | 参数说明 |
---|---|
pattern | 一个字符串形式的正则表达式 |
flags | 可选参数,表示匹配模式,如是否区分大小写,多行匹配等 |
re.compile()函数返回一个编译的正则表达式对象regex。
正则表达式修饰符
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别匹配 |
re.M | 设置多行模式,多行匹配,影响^和$ |
re.S | 使.匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符,影响\w, \W, \b, \B |
re.X | 设置详细模式,详细模式下可以在正则表达式中添加注释, 可以有空格和换行 |