首页 > Python基础应用 > Python 进阶应用教程 > 26 Python 中使用正则表达式

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,予以删除。
© 2023 PV138 · 站点地图 · 免责声明 · 联系我们 · 问题反馈