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 特殊字符
特殊字符是一些有特殊含义的字符,例如的 ab*c 中的 *,* 之前的字符是 b,* 表示匹配 0 个或者多个 字符 b。下表列出了正则表达式中的特殊字符:
2. 模块 re
2.1 简介
Python 提供了 re 模块,提供正则表达式的模式匹配功能。在 re 模块中定义了如下常用函数:
2.2 正则表达式修饰符
正则表达式可以包含一些可选修饰符来控制匹配的模式。修饰符被指定为一个可选的标志,多个标志可以通过按位 OR(|) 它们来指定,如 re.I | re.M 被设置成 I 和 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,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
函数的使用示例如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.hanma.com’ 中查找模式 ‘w+’
- 该模式匹配连续的小写字符 W
- 如果找到模式匹配的子字符串,则返回一个匹配对象 matchObject
- 在第 3 行,匹配对象 matchObject.group() 方法返回匹配的字符串
- 在第 5 行,匹配对象 matchObject.span() 方法返回一个元组
- 元组的第 0 项,匹配的字符串在原始字符串中的起始位置
- 元组的第 1 项,匹配的字符串在原始字符串中的结束位置
- 1
- 2
- 3
- 4
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.hanma.com’ 中查找模式 ‘W+’
- 该模式匹配连续的大写字符 W
- 如果找不到模式匹配的子字符串,则返回一个 None
- 1
- 2
- 3
- 4
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.hanma.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,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
- 1
- 2
- 3
- 4
- 5
- 6
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.hanma.com’ 中查找模式 ‘o+’
- 该模式匹配连续的小写字符 o
- 如果找到模式匹配的子字符串,则返回一个匹配对象 matchObject
- 在第 3 行,匹配对象 matchObject.group() 方法返回匹配的字符串
- 在第 5 行,匹配对象 matchObject.span() 方法返回一个元组
- 元组的第 0 项,匹配的字符串在原始字符串中的起始位置
- 元组的第 1 项,匹配的字符串在原始字符串中的结束位置
3.3 在字符串的首部进行匹配
- 1
- 2
- 3
- 4
- 5
- 在第 2 行,^a 表示从字符串 ‘abc’ 的首部进行匹配
- 在第 3 行,显示匹配结果不为 None
- 在第 4 行,^a 表示从字符串 ‘xabc’ 的首部进行匹配
- 在第 5 行,显示匹配结果为 None
3.4 在字符串的尾部进行匹配
- 1
- 2
- 3
- 4
- 5
- 在第 2 行,c$ 表示从字符串 ‘abc’ 的尾部进行匹配
- 在第 3 行,显示匹配结果不为 None
- 在第 4 行,c$ 表示从字符串 ‘xabc’ 的尾部进行匹配
- 在第 5 行,显示匹配结果为 None
3.5 匹配一串数字
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 在第 2 行,\d+ 表示匹配 1 个或者多个数字
- 在第 3 行,显示匹配结果不为 None
- 在第 4 行,\d{3} 表示匹配 3 个数字
- 在第 5 行,显示匹配结果不为 None
- 在第 6 行,\d+ 表示匹配 4 个数字
- 在第 7 行,显示匹配结果为 None
3.6 判断是否是合法的变量名
Python 的变量命名规则如下:
- 首个字符必须是字母或者字符 _
- 其余的字符可以是字符、数字或者字符 _
下面的例子使用正则表达式判断字符串是否是一个合法的变量名称:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 在第 3 行,定义了函数 isPythonId(id),判断输入字符串 id 是否是一个合法的 Python 变量名
- 在第 4 行,模式 pattern 定义了一个合法的 Python 变量名的模式,该模式由 4 个部分构成
程序运行输出结果如下:
- 1
- 2
- 3
4. 将字符串分割成多个部分
函数 re.split(pattern, string) 根据分隔符 pattern 将字符串 string 分割
- 返回一个列表,该列表记录了分割的字符串
- 参数 pattern,描述了分隔符的模式
- 参数 string,是被分割的字符串
- 1
- 2
- 3
- 4
- 5
5. 在字符串替换与模式匹配的字符串
5.1 替换字符串
函数 re.sub(pattern, replace, string, count=0, flags=0) 用于替换字符串:
- 在字符串 string 中查找与模式 pattern 匹配的子串,将其替换为字符串 replace
- 参数 replace,是被替换的字符串,也可为一个函数
- 参数 count,模式匹配后替换的最大次数,默认 0 表示替换所有的匹配
- 参数 flags,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 在第 4 行,搜索字符串 line,将与模式 ‘\d+’ 匹配的字符串替换为 ‘NUMBER’
- 模式 ‘\d+’ 匹配多个连续的数字
- 在第 6 行,搜索字符串 line,将与模式 ‘#.*$’ 匹配的字符串替换为 ‘’
- 替换为空字符串,即删除匹配的字符串
- 模式 ‘#.*$’ 匹配从字符 # 开始到到结尾的字符串,即行的注释
程序输出结果:
- 1
- 2
- 在第 1 行,将数字 123 替换为 NUMBER
- 在第 1 行,将以 # 开始的注释删除
5.2 使用函数替换字符串
参数 replace 用于替换匹配的字符串,它可以是一个函数。下面的例子将匹配的数字乘以 2:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 在第 8 行,定义了原始字符串 line
- 在第 9 行,使用 re.sub 搜索符合模式 ‘\d+’ 的字符串,使用函数 replace 进行替换
- re.sub 找到符合模式 ‘\d+’ 的字符串时,将匹配结果传递给 replace
- 函数 replace 根据匹配结果,返回一个字符串
- re.sub 将符合模式的字符串替换为函数 replace 的返回结果
- 在第 3 行,定义了函数 replace
- 在第 4 行,matchedObject.group() 返回匹配模式的字符串
- 在第 5 行,将匹配的字符串转换为整数
- 在第 6 行,将整数乘以 2 后转换为字符串,并返回
程序输出结果如下:
- 1
6. 分组与捕获
6.1 简介
正则表达式中的分组又称为子表达式,就是把一个正则表达式的全部或部分当做一个整体进行处理,分成一个或多个组。其中分组是使用 () 表示的。进行分组之后 ()里面的内容就会被当成一个整体来处理。
把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用,被称为捕获。
6.2 分析 URL
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 在第 3 行,函数 parseUrl(url) 分析 URL 的组成部分
- URL 由 3 部分构成:协议、主机名、路径名
- 在第 4 行,定义了匹配 URL 的模式 ‘(.)://(.)/(.*)’
- 第 1 个 (.*) 匹配协议
- 第 2 个 (.*) 匹配主机名
- 第 3 个 (.*) 匹配路径名
- 匹配对象 matchObject 的 group(index) 方法返回指定分组号的分组
- group(0) 为匹配整个表达式的字符串
- group(1) 为匹配的协议
- group(2) 为匹配的主机名
- group(3) 为匹配的路径名
程序运行输出:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9