Python 中使用正则表达式
1. 正则表达式
1.1 简介
正则表达式 (regular expression) 描述了一种字符串匹配的模式 (pattern),例如:
- 模式 ab+c 
- 可以匹配 abc、abbc、abbbc
 - 
- 代表前面的字符出现 1 次或者多次
 
 
 - 模式 ab*c 
- 可以匹配 ac、abc、abbc
 - ? 代表前面的字符出现 0 次或者多次
 
 - 模式 ab?c 
- 可以匹配 ac、abc
 - ? 代表前面的字符出现 0 次或者 1 次
 
 
它的用途包括:
- 检查一个串是否含有某种子串
 - 将匹配的子串替换
 - 从某个串中取出符合某个条件的子串
 
1.2 普通字符
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有大写和小写字母、所有数字、所有标点符号和一些其他符号。
1.3 特殊字符
特殊字符是一些有特殊含义的字符,例如的 abc 中的 , 之前的字符是 b, 表示匹配 0 个或者多个 字符 b。下表列出了正则表达式中的特殊字符:
| 特殊字符 | 描述 | 
|---|---|
| \t | 制表符 | 
| \f | 换页符 | 
| \n | 换行符 | 
| \r | 回车符 | 
| \s | 匹配任意空白字符,等价于 [\t\n\r\f] | 
| \S | 匹配任意非空字符 | 
| \d | 匹配任意数字,等价于 [0-9] | 
| \D | 匹配任意非数字 | 
| ^ | 匹配字符串的开头 | 
| $ | 匹配字符串的末尾 | 
| . | 匹配任意字符 | 
| \b | 匹配一个单词边界,在单词的开头或者末尾匹配xcd ef’ | 
| \B | 匹配非单词边界 | 
| […] | 用来表示一组字符 | 
| [^…] | 不在[]中的字符 | 
| re* | 匹配 0 个或多个正则表达式 | 
| re+ | 匹配 1 个或多个正则表达式 | 
| re? | 匹配 0 个或 1 个正则表达式 | 
| re{n} | 匹配 n 个正则表达式 | 
| re{n,m} | 匹配 n 到 m 个正则表达式 | 
| a | b | 
| (re) | 对正则表达式分组并记住匹配的文本 | 
2. 模块 re
2.1 简介
Python 提供了 re 模块,提供正则表达式的模式匹配功能。在 re 模块中定义了如下常用函数:
| 函数 | 功能 | 
|---|---|
| re.match(pattern, string, flags) | 从字符串 string 的 起始位置 ,查找符合模式 pattern 的子串 | 
| re.search(pattern, string, flags) | 从字符串 string 的 任意位置 ,查找符合模式 pattern 的子串 | 
| re.split(pattern, string) | 根据分隔符 pattern 将字符串 string 分割 | 
| re.sub(pattern, replace, string) | 将字符串中匹配模式 patter 的子串替换字符串 replace | 
2.2 正则表达式修饰符
正则表达式可以包含一些可选修饰符来控制匹配的模式。修饰符被指定为一个可选的标志,多个标志可以通过按位 OR(|) 它们来指定,如 re.I | re.M 被设置成 I 和 M 标志。下表列举了常用的正则表达式修饰符:
| 修饰符 | 描述 | 
|---|---|
| re.I | 使匹配对大小写不敏感 | 
| re.M | 多行匹配,影响 ^ 和 $ | 
2.3 re.MatchObject
re.MatchObject 表示模式匹配的结果,该对象包含 3 个成员方法:
- start() 返回匹配开始的位置
 - end() 返回匹配结束的位置
 - span() 返回一个元组包含匹配 (开始,结束) 的位置
 
2.4 re.RegexObject
re.RegexObject 表示正则表示对象,该对象包含 2 个成员方法:
- match(string) | 从字符串 string 的 起始位置 ,查找符合模式 pattern 的子串
 - serach(string) | 从字符串 string 的 任意位置 ,查找符合模式 pattern 的子串
 
3. 在字符串查找与模式匹配的字符串
3.1 从字符串的起始位置进行匹配
函数 re.match(pattern, string, flags = 0) 用于在字符串查找与模式匹配的字符串:
- 从字符串 string 的 起始位置 ,查找符合模式 pattern 的子串
 - 如果匹配成功,则返回一个 re.MatchObject 对象
 - 如果匹配失败,则返回 None
 - 参数 flags,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
 
函数的使用示例如下:
>>> import re
>>> matchObject = re.match('w+', 'www.imooc.com')
>>> matchObject.group()
'www'
>>> matchObject.span()
(0, 3)
- 在第 1 行,导入模块 re
 - 在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘w+’ 
- 该模式匹配连续的小写字符 W
 - 如果找到模式匹配的子字符串,则返回一个匹配对象 matchObject
 
 - 在第 3 行,匹配对象 matchObject.group() 方法返回匹配的字符串
 - 
在第 5 行,匹配对象 matchObject.span() 方法返回一个元组
- 元组的第 0 项,匹配的字符串在原始字符串中的起始位置
 - 元组的第 1 项,匹配的字符串在原始字符串中的结束位置
 
import re matchObject = re.match('W+', 'www.imooc.com') matchObject is None True
 - 
在第 1 行,导入模块 re
 - 
在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘W+’
- 该模式匹配连续的大写字符 W
 - 如果找不到模式匹配的子字符串,则返回一个 None
 
import re matchObject = re.match('o+', 'www.imooc.com') matchObject is None True
 - 
在第 1 行,导入模块 re
 - 在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘o+’ 
- 该模式匹配连续的小写字符 o
 - 如果找不到模式匹配的子字符串,则返回一个 None
 
 - 在第 4 行,显示匹配结果是 None 
- 尽管字符 string 的中间含有字符串 oo
 - 函数 re.match 从字符串 string 的开始位置进行匹配
 - 因此找不到匹配
 
 
3.2 从字符串的任意位置进行匹配
函数 re.search(pattern, string, flags = 0) 用于在字符串查找与模式匹配的字符串:
- 从字符串 string 的 任意位置 ,查找符合模式 pattern 的子串
 - 如果匹配成功,则返回一个 re.MatchObject 对象
 - 如果匹配失败,则返回 None
 - 
参数 flags,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
import re matchObject = re.search('o+', 'www.imooc.com') matchObject.group() 'oo' matchObject.span() (6, 8)
 - 
在第 1 行,导入模块 re
 - 在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘o+’ 
- 该模式匹配连续的小写字符 o
 - 如果找到模式匹配的子字符串,则返回一个匹配对象 matchObject
 
 - 在第 3 行,匹配对象 matchObject.group() 方法返回匹配的字符串
 - 在第 5 行,匹配对象 matchObject.span() 方法返回一个元组 
- 元组的第 0 项,匹配的字符串在原始字符串中的起始位置
 - 元组的第 1 项,匹配的字符串在原始字符串中的结束位置
 
 
3.3 在字符串的首部进行匹配
>>> import re
>>> re.search('^a', 'abc')
<_sre.SRE_Match object; span=(0, 1), match='a'>
>>> re.search('^a', 'xabc')
>>>
- 在第 2 行,^a 表示从字符串 ‘abc’ 的首部进行匹配 
- 在第 3 行,显示匹配结果不为 None
 
 - 在第 4 行,^a 表示从字符串 ‘xabc’ 的首部进行匹配 
- 在第 5 行,显示匹配结果为 None
 
 
3.4 在字符串的尾部进行匹配
>>> import re
>>> re.search('c$', 'abc')
<_sre.SRE_Match object; span=(2, 3), match='c'>
>>> re.search('c$', 'abcx')
>>>
- 在第 2 行,c$ 表示从字符串 ‘abc’ 的尾部进行匹配 
- 在第 3 行,显示匹配结果不为 None
 
 - 在第 4 行,c$ 表示从字符串 ‘xabc’ 的尾部进行匹配 
- 在第 5 行,显示匹配结果为 None
 
 
3.5 匹配一串数字
>>> import re
>>> re.search('\d+', 'abc123xyz')
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> re.search('\d{3}', 'abc123xyz')
<_sre.SRE_Match object; span=(3, 6), match='123'>
>>> re.search('\d{4}', 'abc123xyz')
>>>
- 在第 2 行,\d+ 表示匹配 1 个或者多个数字 
- 在第 3 行,显示匹配结果不为 None
 
 - 在第 4 行,\d{3} 表示匹配 3 个数字 
- 在第 5 行,显示匹配结果不为 None
 
 - 在第 6 行,\d+ 表示匹配 4 个数字 
- 在第 7 行,显示匹配结果为 None
 
 
3.6 判断是否是合法的变量名
Python 的变量命名规则如下:
- 首个字符必须是字母或者字符 _
 - 其余的字符可以是字符、数字或者字符 _
 
下面的例子使用正则表达式判断字符串是否是一个合法的变量名称:
import re
def isPythonId(id):
    pattern = '^[a-zA-Z_][a-zA-Z0-9_]*$'
    matchObject = re.search(pattern, id)
    if matchObject is None:
        print('%s is not Id' % id)
    else:
        print('%s is Id' % id)
isPythonId('abc') 
isPythonId('Abc_123') 
isPythonId('123')
- 在第 3 行,定义了函数 isPythonId(id),判断输入字符串 id 是否是一个合法的 Python 变量名
 - 在第 4 行,模式 pattern 定义了一个合法的 Python 变量名的模式,该模式由 4 个部分构成
 
| 模式 | 功能 | 
|---|---|
| ^ | 匹配字符串头部,即被匹配的字符串从原始字符串的头部开始 | 
| [a-zA-Z_] | 匹配小写字符、大写字符和字符 _ | 
| [a-zA-Z0-9_] | 匹配小写字符、大写字符、数字和字符 _ | 
| * | 将 * 之前的字符重复 0 次或者多次 | 
| $ | 匹配字符串尾部,即被匹配的字符串以原始字符串的尾部结尾 | 
程序运行输出结果如下:
abc is Id
Abc_123 is Id
123 is not Id
4. 将字符串分割成多个部分
函数 re.split(pattern, string) 根据分隔符 pattern 将字符串 string 分割
- 返回一个列表,该列表记录了分割的字符串
 - 参数 pattern,描述了分隔符的模式
 - 
参数 string,是被分割的字符串
import re re.split('[ :]', 'www imooc:com') ['www', 'imooc', 'com'] re.split(' +', 'www imooc com') ['www', 'imooc', 'com']
 
5. 在字符串替换与模式匹配的字符串
5.1 替换字符串
函数 re.sub(pattern, replace, string, count=0, flags=0) 用于替换字符串:
- 在字符串 string 中查找与模式 pattern 匹配的子串,将其替换为字符串 replace
 - 参数 replace,是被替换的字符串,也可为一个函数
 - 参数 count,模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
 - 
参数 flags,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
import re
line = 'number = 123 # this is comment' result = re.sub('\d+', 'NUMBER', line) print(result) result = re.sub('#.*$', '', line) print(result)
 - 
在第 4 行,搜索字符串 line,将与模式 ‘\d+’ 匹配的字符串替换为 ‘NUMBER’
- 模式 ‘\d+’ 匹配多个连续的数字
 
 - 在第 6 行,搜索字符串 line,将与模式 ‘#.*$’ 匹配的字符串替换为 ‘’ 
- 替换为空字符串,即删除匹配的字符串
 - 模式 ‘#.*$’ 匹配从字符 # 开始到到结尾的字符串,即行的注释
 
 
程序输出结果:
number = NUMBER # this is comment
number = 123
- 在第 1 行,将数字 123 替换为 NUMBER
 - 在第 1 行,将以 # 开始的注释删除
 
5.2 使用函数替换字符串
参数 replace 用于替换匹配的字符串,它可以是一个函数。下面的例子将匹配的数字乘以 2:
import re
def replace(matchedObject):
    text = matchedObject.group()
    number = int(text)
    return str(number * 2)
line = 'number = 123'
result = re.sub('\d+', replace, line)
print(result)
- 在第 8 行,定义了原始字符串 line
 - 在第 9 行,使用 re.sub 搜索符合模式 ‘\d+’ 的字符串,使用函数 replace 进行替换 
- re.sub 找到符合模式 ‘\d+’ 的字符串时,将匹配结果传递给 replace
 - 函数 replace 根据匹配结果,返回一个字符串
 - re.sub 将符合模式的字符串替换为函数 replace 的返回结果
 
 - 在第 3 行,定义了函数 replace 
- 在第 4 行,matchedObject.group() 返回匹配模式的字符串
 - 在第 5 行,将匹配的字符串转换为整数
 - 在第 6 行,将整数乘以 2 后转换为字符串,并返回
 
 
程序输出结果如下:
number = 246
6. 分组与捕获
6.1 简介
正则表达式中的分组又称为子表达式,就是把一个正则表达式的全部或部分当做一个整体进行处理,分成一个或多个组。其中分组是使用 () 表示的。进行分组之后 ()里面的内容就会被当成一个整体来处理。
把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,被称为捕获。
6.2 分析 URL
import re
def parseUrl(url):
    pattern = '(.*)://(.*)/(.*)'
    matchObject = re.search(pattern, url)
    all = matchObject.group(0)
    protocol = matchObject.group(1)
    host = matchObject.group(2)
    path = matchObject.group(3)
    print('group(0) =', all)
    print('group(1) =', protocol)
    print('group(2) =', host)
    print('group(3) =', path)
    print()
parseUrl('https://www.imooc.com/wiki')
parseUrl('http://www.imooc.com/courses')
- 在第 3 行,函数 parseUrl(url) 分析 URL 的组成部分 
- URL 由 3 部分构成:协议、主机名、路径名
 
 - 在第 4 行,定义了匹配 URL 的模式 ‘(. )://(. )/(.*)’ 
- 第 1 个 (.*) 匹配协议
 - 第 2 个 (.*) 匹配主机名
 - 第 3 个 (.*) 匹配路径名
 
 - 匹配对象 matchObject 的 group(index) 方法返回指定分组号的分组 
- group(0) 为匹配整个表达式的字符串
 - group(1) 为匹配的协议
 - group(2) 为匹配的主机名
 - group(3) 为匹配的路径名
 
 
程序运行输出:
group(0) = https://www.imooc.com/wiki
group(1) = https
group(2) = www.imooc.com
group(3) = wiki
group(0) = http://www.imooc.com/courses
group(1) = http
group(2) = www.imooc.com
group(3) = courses
访问者可将本网站提供的内容或服务用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯本网站及相关权利人的合法权利。
本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站,邮箱:80764001@qq.com,予以删除。
