一、隨機庫
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']