小白学Python,标准库篇——随机库、正则表达式库
一、随机库
1.随机生成数值
在random库中可以随机生成数值的方法有uniform()、random()、randint()、randrange()等。
(1)uniform()方法
uniform(参数1, 参数2)方法用于生成参数1到参数2之间的随机小数,其中参数的类型都为数值类型。
示例代码:
import random
a = random.uniform(1, 5)
print(a)
执行代码后的输出结果为2.2913853063272107,因为是随机输出的数值,所以每次运行结果都可能不同。
(2)random()方法
random()方法用于生成0~1(不包含1)的随机小数,无须填入参数。
示例代码:
import random
a = random.random()
print(a)
执行代码后的输出结果为0.6109992072802352,因为是随机输出的数值,所以每次运行结果都可能不同。
(3)randint()方法
randint(参数1, 参数2)方法用于生成在参数1到参数2之间的整数。
示例代码:
import random
a = random.randint(2, 9)
print(a)
第2行代码表示在执行代码后将输出一个2~9的整数,结果为5。
(4)randrange()方法
randrange(参数1, 参数2, 参数3)方法用于生成在参数1到参数2之间且步长为参数3的随机整数。
示例代码:
import random
a = random.randrange(0, 20, 5)
print(a)
第2行代码表示从0~20的范围内且步长为5的数值(0、5、10、15)中随机选取一个数值,执行代码后的输出结果为15。
2.随机选择
random库中的choice()、shuffle()、sample()函数可以实现从一些数据中随机选择一个或多个元素。
(1)choice()函数
choice(参数)用于从参数中随机选择一个元素,参数通常是序列类型(可以通过索引的方式获取元素)数据,例如列表、字符串。
示例代码:
import random
ls = ['一等奖', '二等奖', '三等奖', '谢谢惠顾']
a = random.choice(ls)
print(a)
第3行代码从列表ls中随机选取一个元素,与抽奖活动的程序代码相似。执行代码后的输出结果为“谢谢惠顾”。由于是随机从ls中选择一个元素,因此每次运行的结果都可能不同。
(2)shuffle()函数
shuffle(参数)用于将列表ls中的元素顺序随机打乱,参数是序列类型数据。
示例代码:
import random
ls = ['一等奖', '二等奖', '三等奖', '谢谢惠顾']
random.shuffle(ls)
print(ls)
第3行代码使用shuffle()将列表ls中的元素顺序随机打乱。由于是随机从ls中选择一个元素,因此每次运行的结果都可能不同。
代码执行结果:
['一等奖', '二等奖', '谢谢惠顾', '三等奖']
(3)sample()函数
sample(参数1, 参数2)用于从参数1中随机选取参数2个元素,其中参数1为序列类型数据,参数2为整数。
示例代码:
import random
ls = ['一等奖', '二等奖', '三等奖', '谢谢惠顾']
a = random.sample(ls, 2)
print(a)
第3行代码表示从ls列表中随机选择2个元素。
代码执行结果:
['一等奖', '谢谢惠顾']
3.随机种子
在某些场景下并不希望用户每次运行代码后的结果都不相同,例如小王抽奖为“二等奖”,王五抽奖为“谢谢惠顾”,每人只能抽取一种结果,且每次运行结果都相同,这时需要用到随机种子seed()函数。其使用形式如下:
seed(种子)
功能:在随机数中设置一个随机种子,下一次随机获取的值必须由该随机种子发出。
参数种子:可以是任何数据类型的,例如整数类型或字符串类型。
示例代码:
import random
ls = ['一等奖', '二等奖', '三等奖', '谢谢惠顾']
random.seed('张三')
print(random.choice(ls))
random.seed('王五')
print(random.choice(ls))
代码执行结果:
二等奖
谢谢惠顾
二、正则表达式库
匹配字符串表示从字符串中筛选出满足条件的信息,这里的条件要使用一种特殊的表达式,即正则表达式表示。本小节主要介绍3种匹配字符串的方法,分别是re库中的match()函数、search()函数和findall()函数。
1.匹配字符串
(1)match()函数
match()函数的使用形式如下:
match(参数1, 参数2)
功能:表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容,如果参数2起始位置匹配不成功的话,就返回none;如果起始位置匹配成功,就返回匹配的内容。
示例代码:
import re
message = '张三、李四、王五、赵六'
result = re.match('张三', message)
print(result)
第3行代码表示从message字符串中匹配'张三',这里参数2并没有用到正则表达式。由于message中'张三'位于开头,因此可以正确地匹配到。
代码执行结果:
<re.Match object; span=(0, 2), match='张三'>
返回的结果以正则的类型输出,其中span=(0,2)指明匹配的位置,表示在字符串索引号为0~2的位置匹配成功,匹配的内容为'张三'。现将以上代码进行修改,修改后的代码如下:
import re
message = '张三、李四、王五、赵六'
result = re.match('三', message)
print(result)
执行代码后将返回None,虽然字符'三'在message中,但并不位于message的开头,所以匹配不成功。
(2)search()函数
search()函数的使用形式如下:
search(参数1, 参数2)
功能:表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容,如果匹配了多个参数1,则只返回第1个匹配成功的信息。
示例代码:
import re
message = '张三、李四、王五、赵六、王五'
result = re.search('王五', message)
print(result)
第3行代码使用search()函数从message中匹配字符串'王五',由于message中存在两个'王五',因此执行代码后会输出第1个'王五'所在的位置及内容。
代码执行结果:
<re.Match object; span=(6, 8), match='王五'>
(3)findall()函数
findall()函数的使用形式如下:
findall(参数1, 参数2)
功能:表示从参数2(字符串类型数据)中查找满足参数1(正则表达式)的内容,如果匹配了多个参数1,则返回匹配成功的全部信息。
示例代码:
import re
message = '张三、李四、王五、赵六、王五'
result = re.findall('王五', message)
print(result)
findall()并不返回匹配的位置,只返回匹配的全部内容。
代码执行结果:
['王五', '王五']
2.正则表达式
上小节介绍的match()、search()、findall()函数中,参数1均是字符串,并没有涉及正则表达式。正则表达式是一种使用特殊符号表示字符串的规则。本小节将分别从字符范围、字符出现的次数及同一类字符这3个方向来介绍正则表达式。
(1)表达字符范围
[xyz]:字符集合,即匹配所包含的任意一个字符。例如[abc]可以匹配plain中的a。
[a-z]:字符范围,即匹配指定范围内的任意字符。例如[a-z]可以匹配a到z范围内的任意小写字母。
示例代码:
import re
message = 'Python93,C87,Java63,C++88'
result_1 = re.search('[cn]', message)
result_2 = re.findall('[0-9]', message)
result_3 = re.findall('[cn][0-9]', message)
print(result_1, result_2, result_3)
第3行代码表示从message中匹配字符c或n,只要message中包含c或n,执行代码后就会输出匹配到的第一个字符。需要注意的是大写的C是不能匹配的。
第4行代码表示从message中匹配0~9的任何一个数字,即匹配全部数字,由于使用了findall()函数,因此程序会将message中的全部数字输出。
第5行代码中的正则表达式包含[cn][0-9],表示需要匹配两个字符,且第1个字符是c或n、第2个字符是数字。
代码执行结果:
<re.Match object; span=(5, 6), match='n'> ['9', '3', '8', '7', '6', '3', '8', '8'] ['n9']
(2)表示字符出现的次数
*:匹配前面的子表达式任意次(大于等于0次)。例如zo能匹配"z"、"zo"和"zoo",*等价于{0,}。
+:匹配前面的子表达式一次或多次。例如"zo+"能匹配"zo"和"zoo",但不能匹配"z",+等价于{1,}。
?:匹配前面的子表达式0次或一次。例如"do(es)?"可以匹配"do"或"does",?等价于{0,1}。
^:匹配输入行首。
$:匹配输入行尾。
{n}:匹配n次,n为非负整数。例如"o{2}"不能匹配"Bob"中的"o",但是能匹配"food"中的两个"o"。
{n,}:至少匹配n次,n为非负整数。例如"o{2,}"不能匹配"Bob"中的"o",但能匹配"fooooood"中的所有"o"。"{o{1,}}"等价于"o+","o{0,}"则等价于"o*"。
{n,m}:最少匹配n次且最多匹配m次,m和n均为非负整数且n≤m。例如"o{1,3}"将匹配"fooooood"中的前3个"o"和后3个"o"。"o{0,1}"等价于"o?"。请注意,逗号和两个数之间不能有空格。
示例代码:
import re
message = 'da2a7ddbre77yifed777t3fefd7777b'
result = re.findall('[a-z]*[0-9][a-z]', message)
print(result)
第3行代码的正则表达式中的前面为[a-z],表示匹配a~z范围内的任意字符,[a-z]表示前面的表达式范围内的字符可以出现任意多次,[a-z][0-9][a-z]表示匹配的最后一个字符是a~z的字母,倒数第2个字符是一个数字。
代码执行结果:
['da2a', '7d', '7y', '7t', '3f', '7b']
示例代码(验证手机号码的正确性):
import re
phone_num = input("请输入您的手机号码:")
result = re.findall('^1[0-9]{10}$', phone_num)
print(result)
手机号码以1开头且一共有11位数字。在第3行代码中,正则表达式^1[0-9]{10}$
中的^1
表示输入的字符串开头必须是1(当使用match()时,可以不需要^)。[0-9]{10}
表示匹配10个字符,且必须是数字。$
表示匹配到行尾,表示匹配了前面的11个数字后就必须结束。当用户输入的内容超过11位或不足11位时,则不满足手机号码的要求,与正则表达式不匹配,程序将返回[]。例如输入错误的手机号码1377772,验证结果如下:
请输入您的手机号码:1377772
[]
当用户输入的手机号码与正则表达式相匹配时,代码程序将输出匹配的内容。例如输入正确的手机号码:
请输入您的手机号码:15155555555
['15155555555']
示例代码(验证QQ号码是否合规):
import reQQ_number = input("请输入您的QQ号:")
result = re.match('^[1-9][0-9]{4,10}$', QQ_number)
print(result)
QQ号码的位数为5~11位,且第1个数字不能为0。第3行代码使用了match(),需要从输入的首字符开始匹配,因此匹配的正则表达式可以省略^,$表示匹配到最后一个字符。如果输入的内容与正则表达式匹配,则会输出匹配的内容;如果匹配失败则会输出None。
示例代码(验证网站用户名的正确性):
import re
user_name = input("请输入您的用户名:")
result = re.findall('^[A-Za-z_][A-Za-z0-9_]{7,}$', user_name)
print(result)
网站用户名由字母(大小写均可)、数字和下画线组成,数字不能用作开头,且用户名长度要大于8。第3行代码中正则表达式^[A-Za-z_][A-Za-z0-9_]{7,}$
表示输入的内容首字母必须是A~Z、a~z或_,[A-Za-z0-9_]{7,}
表示至少匹配7个范围是A~Z、a~z、0~9或_的字符。$表示一直匹配到结尾,结尾的字符也要满足范围是A~Z、a~z、0~9或_。
(3)表示同一类字符
\d: 匹配一个数字类字符,等价于[0-9]。
\D: 匹配一个非数字类字符,等价于[^0-9]。^在方括号中表示非,即不匹配输入字符的首位字符。
\s: 匹配任何不可见字符,包括空格、制表符、分页符等,等价于[\f\n\r\t\v]。
\S: 匹配任何可见字符,等价于[^f\n\r\t\v]。
\w: 匹配包括下画线的任何单词字符,等价于"[A-Za-z0-9_]"。
\W: 匹配任何不包括下画线的非单词字符,等价于"^[A-Za-z0-9_]"。
\b: 匹配一个单词的边界,即单词中与空格邻接的字符。
\B: 匹配非单词边界。例如 “er\B” 能匹配 “verb” 中的 “er”,但不能匹配 “never” 中的 “er”,因为 “er” 是 “never” 的单词边界。
\f: 匹配一个分页符。
\n: 匹配一个换行符。
\r: 匹配一个回车符。
\t: 匹配一个制表符。
\v: 匹配一个垂直制表符。
.: 匹配除 “\n” 和 “\r” 之外的任何单个字符。
示例代码(验证用户名的正确性):
import re
user_name = input("请输入您的用户名:")
result = re.findall(r'^[A-Za-z_]\w{3,}$', user_name)
print(result)
第3行代码中使用正则表达式\w替换了上一示例代码中的[A-Za-z0-9_],效果与上一示例代码的效果相同。
代码执行结果1(输入正确的用户名):
请输入您的用户名:chaoxiang1234
['chaoxiang1234']
代码执行结果2(输入错误的用户名):
请输入您的用户名:chaoxiang12344
[]
示例代码(匹配非单词边界):
import re
message = 'verb very never every'
result = re.findall(r'\wer\B', message) # b是转义字符
print(result)
在第3行代码中,正则表达式r'\wer\B'
中的第一个r表示取消转义字符,因此不需要使用\\
的形式。\wer\B
中\w
表示从message中匹配出开头部分有一个或多个单词的部分,er\B
表示在 message 中匹配出er不是单词的边界的部分。
代码执行结果:
['ver', 'ver', 'ever']
由于verb中的er并不是单词的边界,且er的前面有一个单词v,因此此字符串将会被匹配上。very中的ver也能被匹配上。由于never中的er是单词的边界,因此不会被匹配上。every中的er不是单词的边界,且er的前面有单词ev,因此匹配的内容是ever。
示例代码:
import re
message = 'verb very never every'
result = re.findall(r'.e', message)
print(result)
第3行代码中的正则表达式为'.e',表示从message中匹配两个字符,第1个字符是除"\n"和"\r"之外的任何单个字符,第2个字符是e。
代码执行结果:
['ve', 've', 'ne', 've', ' e', 've']
其中第1个've'从'verb'中匹配获取;第2个've'从'very'中匹配获取;第3个'ne'从'never'中匹配获取;第4个've'从'never'中获取;第5个' e'从'every'中的e和前面的空格匹配获取,由于'.'可以匹配除"\n" 和"\r"之外的任何单个字符,因此'.e'可以匹配空格和'e';第6个've'从'every'中匹配获取。
3.贪婪和非贪婪模式
贪婪和非贪婪模式指是否匹配更多内容,具体使用如下。
(1)贪婪模式
贪婪模式:默认匹配模式都是贪婪模式,匹配形式是尝试匹配尽可能多的字符,只要满足正则表达式要求就会匹配最多的字符。
示例代码(默认匹配模式为贪婪模式):
import re
message = 'ccc739134792hd'
result = re.findall('ccc\d+', message)
print(result)
第3行代码表示从message中匹配前3个字符为'ccc'的字符,其中\d
表示匹配一个数字字符,+表示匹配前面的子表达式一次或多次,即表示匹配一次或多次数字。由于默认匹配模式是贪婪模式,因此会尽可能多地匹配数字。当从'ccc739134792hd'中匹配到了'ccc7'之后还会继续匹配尽可能多的数字。
代码执行结果:
['ccc739134792']
(2)非贪婪模式
非贪婪模式:匹配形式是尝试匹配尽可能少的字符,一旦满足正则表达式要求就不再继续匹配。在次数限制操作符后面加上“?”可以将匹配模式转换为非贪婪模式。
示例代码(将匹配模式转换为非贪婪模式):
import re
message = 'ccc739134792hd'
result = re.findall('ccc\d+?', message)
print(result)
该代码与上一个示例代码的区别在于第3行的正则表达式部分最后增加了一个“?”,表示使用非贪婪模式匹配,只要匹配到'ccc'且后面有一个数字就不会再继续往后匹配。
代码执行结果:
['ccc7']
4.或和组
如果需要筛选出组合条件下的字符数据,可以使用或。如果需要筛选后的某部分内容,可以使用组。
(1)或
或:用“|”表示,表示将两个匹配条件进行逻辑“或”(or)运算。
示例代码(匹配表达式中两个匹配条件中的一个匹配条件):
import re
message = 'verb very never every'
result = re.findall('\w+ev|\w+ry', message)
print(result)
第3行代码使用|表示从message中匹配满足'\w+ev'条件或者满足'\w+ry'条件的内容。'\w+ev'表示匹配一个或多个单词字符,且后面的字符为ev。'\w+ry'表示匹配一个或多个单词字符,且后面的字符为ry。
代码执行结果:
['very', 'nev', 'every']
(2)组
组:用“(表达式)”表示,表示将()中的表达式定义为组,并且将匹配这个表达式的字符保存到一个临时区域(一个正则表达式中最多可以保存9个组)。
示例代码(使用组的形式获取组中的内容):
import re
message = 'verb very never every'
result = re.findall("e(.+)(.)r", message)
print(result)
第3行代码使用了组的形式,表示从'verb very never every'中匹配满足"e(.+)(.)r"条件的内容。因此匹配的内容第1个字符是e,第1个组匹配一个或多个除"\n"和"\r"之外的任何单个字符(包含空格),默认使用贪婪模式进行匹配,该模式会尽可能多地匹配内容。第2个组匹配除“\n”和“\r”之外的任何单个字符(包含空格)。即从字符串的第1个字符e开始,可以一直匹配到最后一个字符r,因此匹配的内容是'er b very never ever'。但输出时只会输出组中的内容,并不会将所有匹配的内容输出,由于有两个组,因此会输出这两个组中的内容。
代码执行结果:
[('rb very never ev', 'e')]
5.sub()和compile()方法
sub()和compile()方法分别用于将字符进行替换和将字符串转换为正则表达式。
(1)sub()方法
sub()方法的使用形式如下,即将字符串参数3中所有与参数1匹配的字符从替换为参数2。
sub(参数1,参数2,参数3)
示例代码:
import re
content = 'dh932hf9f934hfnf39d'
content = re.sub('\d', '0', content)
print(content)
第3行代码将字符串content中满足正则表达式'\d'的内容全部替换为0。
代码执行结果:
dh000hf0f000hfnf00d
(2)compile()方法
compile()方法用于创建一个正则表达式对象,可以直接使用正则表达式对象的方法匹配其他内容。
示例代码:
import re
content1 = '2020 12 15 12:00'
pattern = re.compile('\d{2}:\d{2}')
print(pattern.findall(content1))
第3行代码通过compile()方法创建了一个正则表达式对象pattern,正则表达式的内容为'\d{2}:\d{2}',接下来可以直接使用pattern对象匹配其他内容。第4行代码直接使用pattern.方法的形式,匹配content1中满足pattern正则表达式对象的信息。
代码执行结果:
['12:00']