欢迎大家来到IT世界,在知识的湖畔探索吧!
本文首发自「慕课网」,想了解更多IT干货内容,程序员圈内热闻,欢迎关注!
作者| 慕课网精英讲师 朱广蔚
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。下表列出了正则表达式中的特殊字符:
特殊字符 |
描述 |
\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 |
匹配 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)
代码块123456
欢迎大家来到IT世界,在知识的湖畔探索吧!
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘w+’该模式匹配连续的小写字符 W如果找到模式匹配的子字符串,则返回一个匹配对象 matchObject
- 在第 3 行,匹配对象 matchObject.group() 方法返回匹配的字符串
- 在第 5 行,匹配对象 matchObject.span() 方法返回一个元组元组的第 0 项,匹配的字符串在原始字符串中的起始位置元组的第 1 项,匹配的字符串在原始字符串中的结束位置
欢迎大家来到IT世界,在知识的湖畔探索吧!>>> import re
>>> matchObject = re.match('W+', 'www.imooc.com')
>>> matchObject is None
True
代码块1234
- 在第 1 行,导入模块 re
- 在第 2 行,在字符串 ‘www.imooc.com’ 中查找模式 ‘W+’该模式匹配连续的大写字符 W如果找不到模式匹配的子字符串,则返回一个 None
>>> import re
>>> matchObject = re.match('o+', 'www.imooc.com')
>>> matchObject is None
True
代码块1234
- 在第 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,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等
欢迎大家来到IT世界,在知识的湖畔探索吧!>>> import re
>>> matchObject = re.search('o+', 'www.imooc.com')
>>> matchObject.group()
'oo'
>>> matchObject.span()
(6, 8)
代码块123456
- 在第 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')
>>>
代码块12345
- 在第 2 行,^a 表示从字符串 ‘abc’ 的首部进行匹配在第 3 行,显示匹配结果不为 None
- 在第 4 行,^a 表示从字符串 ‘xabc’ 的首部进行匹配在第 5 行,显示匹配结果为 None
3.4 在字符串的尾部进行匹配
>>> import re
>>> re.search('c#39;, 'abc')
<_sre.SRE_Match object; span=(2, 3), match='c'>
>>> re.search('c#39;, 'abcx')
>>>
代码块12345
- 在第 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')
>>>
代码块1234567
- 在第 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_]*#39;
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')
代码块12345678910111213
- 在第 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
代码块123
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']
代码块12345
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('#.*#39;, '', line)
print(result)
代码块1234567
- 在第 4 行,搜索字符串 line,将与模式 ‘\d+’ 匹配的字符串替换为 ‘NUMBER’模式 ‘\d+’ 匹配多个连续的数字
- 在第 6 行,搜索字符串 line,将与模式 ‘#.*$’ 匹配的字符串替换为 ‘’替换为空字符串,即删除匹配的字符串模式 ‘#.*$’ 匹配从字符 # 开始到到结尾的字符串,即行的注释
程序输出结果:
number = NUMBER # this is comment
number = 123
代码块12
- 在第 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)
代码块12345678910
- 在第 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
代码块1
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')
代码块12345678910111213141516171819
- 在第 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
代码块123456789
欢迎关注「慕课网」,发现更多IT圈优质内容,分享干货知识,帮助你成为更好的程序员!
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/34574.html