您好,登錄后才能下訂單哦!
這篇文章主要介紹“怎么理解并掌握python正則表達(dá)式和re模塊”,在日常操作中,相信很多人在怎么理解并掌握python正則表達(dá)式和re模塊問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”怎么理解并掌握python正則表達(dá)式和re模塊”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!
1.正則表達(dá)式
正則表達(dá)式,又稱(chēng)規(guī)則表達(dá)式。(英語(yǔ):Regular Expression,在代碼中常簡(jiǎn)寫(xiě)為regex、regexp或RE),計(jì)算機(jī)科學(xué)的一個(gè)概念。正則表達(dá)式通常被用來(lái)檢索、替換那些符合某個(gè)模式(規(guī)則)的文本。
下面是正則表達(dá)式常見(jiàn)的使用場(chǎng)景:
檢查字符串的合法性
驗(yàn)證用戶(hù)名 (a-z,0-9,不能全是數(shù)字,不能全是字母)
驗(yàn)證郵箱格式 (xxx@qq.com)
驗(yàn)證電話(huà)號(hào)碼 (11位數(shù)字)
驗(yàn)證身份證 (18位 )
驗(yàn)證號(hào)碼格式(5-12純數(shù)字,第一位不能為0);
提取字符串中信息
提取一條短信中數(shù)字;
提取文件名的后綴;
采集器(網(wǎng)絡(luò)爬蟲(chóng))
替換字符串
替換字符串中的非法字符;
對(duì)電話(huà)號(hào)碼進(jìn)行屏蔽;(1852****0102)
替換占位符 “hello {{name}} ” hello 王老二 (模板框架)
分割字符串
將一個(gè)字符串按照指定的規(guī)則進(jìn)行分割;
通俗地說(shuō),正則的功能是檢索特定形式的字符串,對(duì)象是字符串。
1.1 元字符
使用元字符匹配單個(gè)字符
字符 功能
. 匹配任意1個(gè)字符(除了\n)
[ ] 匹配[ ]中列舉的字符
\d 匹配數(shù)字,即0-9
\D 匹配非數(shù)字,即不是數(shù)字
\s 匹配空白,即 空格,tab鍵
\S 匹配非空白
\w 匹配單詞字符,即a-z、A-Z、0-9、_
\W 匹配非單詞字符
* 匹配前一個(gè)字符出現(xiàn)0次或者無(wú)限次,即可有可無(wú)
+ 匹配前一個(gè)字符出現(xiàn)1次或者無(wú)限次,即至少有1次
import re
text = '''
這是用來(lái)匹配的字符串
from:1427319758@qq.com
tel:88888888
'''
針對(duì)上述字符串進(jìn)行元字符的正則匹配演示
使用點(diǎn).匹配任意字符
res = re.findall('.',text)
print(res)
運(yùn)行結(jié)果(注意返回的是列表):
['這', '是', '用', '來(lái)', '匹', '配', '的', '字', '符', '串', 'f', 'r', 'o', 'm', ':', '1', '4', '2', '7', '3', '1', '9', '7', '5', '8', '@', 'q', 'q', '.', 'c', 'o', 'm', 't', 'e', 'l', ':', '8', '8', '8', '8', '8', '8', '8', '8']
\d匹配數(shù)字
res = re.findall('\d',text)
print(res)
運(yùn)行結(jié)果:
['1', '4', '2', '7', '3', '1', '9', '7', '5', '8', '8', '8', '8', '8', '8', '8', '8', '8']
+ * 匹配多個(gè)字符
res = re.findall('\d+',text)
res_1 = re.findall('\d*',text)
print(res,res_1)
運(yùn)行結(jié)果:
['1427319758', '88888888']
['', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '1427319758', '', '', '', '', '', '', '', '', '', '', '', '', '88888888', '', '']
*匹配前一字符可以是0次,因此\d*會(huì)匹配每個(gè)不是數(shù)字的字符,即為空。\d+等同\d\d*
[](字符集)
人為規(guī)定只能匹配出現(xiàn)在字符集中的字符,如要找尋字符串中的qq號(hào),qq號(hào)不能以0開(kāi)頭,且位數(shù)是5~12
可用[1-9]\d{4,11}來(lái)限制
郵箱可能出現(xiàn)為字符串,可用[1-9a-zA-Z]\w+[@]\w+[.][a-zA-z]+可以匹配出任意常規(guī)格式的郵箱
res = re.findall('[1-9a-zA-Z]\w+[@]\w+[.][a-zA-z]+','''
1427319758@163.com開(kāi)會(huì)就
1427319758@edu.cn是否
1427319758@xx.mail 阿薩德
asdfbglsafhlf上單發(fā)順豐打打分
''')
print(res)
運(yùn)行結(jié)果:
['1427319758@163.com', '1427319758@edu.cn', '1427319758@xx.mail']
使用.*匹配任意多個(gè)字符
res = re.findall('.*',text)
print(res)
運(yùn)行結(jié)果:
['', '這是用來(lái)匹配的字符串', '', 'from:1427319758@qq.com', '', 'tel:88888888', '', '']
由于re.findall()函數(shù)默認(rèn)遇到換行符 '\n’會(huì)終止當(dāng)前的匹配,即不匹配換行符,每一行單獨(dú)匹配,因此會(huì)出現(xiàn)空元素。
1.2 數(shù)量詞
使用數(shù)量詞匹配多個(gè)字符
字符 功能
{m} 匹配前一個(gè)字符出現(xiàn)m次
{m,n} 匹配前一個(gè)字符出現(xiàn)從m到n次
限制匹配字符出現(xiàn)的次數(shù)
res = re.findall('[1-9]\d{4,11}',text)
res_1 = re.findall('([1-9]\d{4,11})@',text)
print(res,res_1)
運(yùn)行結(jié)果:
['1427319758', '88888888'] ['1427319758']
第一種方式匹配了同樣滿(mǎn)足規(guī)則的手機(jī)號(hào),第二種方式是考慮到qq號(hào)隱藏在郵箱地址里,所以在后面加了@來(lái)限制匹配的區(qū)域,即只匹配@前的第1位非0的5-12位純數(shù)字。
1.3 精確匹配與泛匹配
泛匹配
泛匹配是匹配包括特征字符在內(nèi)的所有的東西
res = re.findall('Hello.*like','Hello world! I like python!')
print(res)
運(yùn)行結(jié)果:
['Hello world! I like']
精確匹配
精確匹配是匹配括號(hào)里面的東西
res_1 = re.findall('Hello(.*)like','Hello world! I like python!')
print(res_1)
運(yùn)行結(jié)果:
[' world! I ']
我想要Hello和like之間的字符,泛匹配的結(jié)果會(huì)包含首尾的特征字符Hello和like;而精確匹配只會(huì)得到特征字符之間的字符串。
1.4 貪婪匹配與非貪婪匹配
Python里數(shù)量詞默認(rèn)是貪婪的(在少數(shù)語(yǔ)言里也可能是默認(rèn)非貪婪),總是嘗試匹配盡可能多的字符;
非貪婪則相反,總是嘗試匹配盡可能少的字符。
在"*","?","+","{m,n}"后面加上?,使貪婪變成非貪婪。
res = re.findall('Hello(.*)like','Hello world! I like python! I like you!')
res_1 = re.findall('Hello(.*?)like','Hello world! I like python! I like you!')
print(res,res_1)
運(yùn)行結(jié)果:
[' world! I like python! I ']
[' world! I ']
res返回的是貪婪匹配,它會(huì)在找到Hello后,匹配盡可能多的字符,然后在最后一個(gè)like停下;
res_1返回的是非貪婪匹配,它在找到Hello后,只匹配第一個(gè)like前的字符。
2. re模塊
一直以來(lái)我們都是使用 re.search() 函數(shù),其實(shí)在正則表達(dá)式模塊中還有一些函數(shù)可以很方便的對(duì)字符串進(jìn)行操作。re模塊的使用可以分為兩種:第一種是對(duì)象式的方式,第二種是函數(shù)式的方式。
2.1 re.match
match() 用于查找字符串的頭部(也可以指定起始位置),它是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回,而不是查找所有匹配的結(jié)果。它的一般使用形式如下:
match(pattern, string[, flag])
其中,pattern是正則表達(dá)式規(guī)則字符串,string 是待匹配的字符串,flag 是可選參數(shù)。
當(dāng)匹配成功時(shí),返回一個(gè) Match 對(duì)象,如果沒(méi)有匹配上,則返回 None。
import re
pattern = 'Python'
string = 'dsgfaPythonahsdgjasghPythonasdjajsk'
result = re.match(pattern,string)
result_1 = re.match(pattern,string[5:])
print(result,result_1)
運(yùn)行結(jié)果:
None
<_sre.SRE_Match object; span=(0, 6), match='Python'>
2.2 re.search
search() 用于查找字符串的任何位置,它也是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回,而不是查找所有匹配的結(jié)果,它的一般使用形式如下:
search(pattern, string[, flag])
當(dāng)匹配成功時(shí),返回一個(gè) Match 對(duì)象,如果沒(méi)有匹配上,則返回 None。
ret = re.search('\d+', "python = 9999, c = 7890, c++ = 12345")
print(ret.group())
運(yùn)行結(jié)果:
9999
2.3 re.findall 劃重點(diǎn)!
上面的 match 和 search 方法都是一次匹配,只要找到了一個(gè)匹配的結(jié)果就返回。然而,在大多數(shù)時(shí)候,我們需要搜索整個(gè)字符串,獲得所有匹配的結(jié)果。findall() 的使用形式如下:
findall(pattern, string[, flag])
findall() 以列表形式返回全部能匹配的子串,如果沒(méi)有匹配,則返回一個(gè)空列表。
ret = re.findall(r"\d+", "python = 9999, c = 7890, c++ = 12345")
print(ret)
運(yùn)行結(jié)果:
['9999', '7890', '12345']
2.4 re.split
split()按照能夠匹配的子串將字符串分割后返回列表,它的使用形式如下:
split(pattern, string[, maxsplit, flags])
其中,maxsplit 用于指定最大分割次數(shù),不指定將全部分割。
'''
split():
分割字符串 去掉了匹配到的字符串
結(jié)果是列表形式
maxsplit: 默認(rèn)是0 表示全部切割
1 代表切割一次
2 代表切割兩次
'''
pattern = '\d+'
string = 'Pythonasdkjasd464654adhuiaghsdk564654akjsdhkashdkja'
result = re.split(pattern,string,2)
print(result)
運(yùn)行結(jié)果:
['Pythonasdkjasd', 'adhuiaghsdk', 'akjsdhkashdkja']
實(shí)際上就是面向字符串操作的string.split的升級(jí)版
2.5 re.sub
sub()用于替換,使用形式如下:
sub(pattern, repl, string[, count, flags])
第一個(gè)參數(shù)為對(duì)應(yīng)的正則表達(dá)式,第二個(gè)參數(shù)為要替換成的字符串,第三個(gè)參數(shù)為源字符串,第四個(gè)參數(shù)為可選項(xiàng),代表最多替換的次數(shù),如果忽略不寫(xiě),則會(huì)將符合模式的結(jié)果全部替換。
pattern = 'Java'
repl = '********'
string = 'kjasdJavaadhuiaghsdkJavaakjsd'
result = re.sub(pattern,repl,string,1)
print(result)
運(yùn)行結(jié)果:
kjasd********adhuiaghsdkJavaakjsd
string.replace的升級(jí)版
參數(shù)flags
方法1:
ret = re.sub("\d+", '18', "age = 12")
print(ret)
運(yùn)行結(jié)果:
age = 18
方法2 用函數(shù):
re.sub()的本質(zhì)是在字符串中檢索符合pattern格式的子串,然后把子串當(dāng)做參數(shù)輸入repl中,默認(rèn)的repl功能可以看成是函數(shù),即不論我輸入的子串是什么樣的,輸出都用repl參數(shù)代替,此處repl無(wú)法跟子串產(chǎn)生關(guān)系
def replace(string,repl):
return repl
如果我們要讓輸出的repl和子串產(chǎn)生關(guān)系,如將字符串中的電話(huà)號(hào)碼15654862043輸出成1565****043,僅僅通過(guò)設(shè)定一個(gè)repl字符串是不能實(shí)現(xiàn)的,就需要在repl處傳入一個(gè)函數(shù)。
import re
text = '''
15654561654
13905641750
15646575635
18976534547
'''
def replace(string):
string = string.group()
repl = string[0:4] + '****' + string[-4:-1]
return repl
ret = re.sub("\d+", repl = replace, string = text)
print(ret)
運(yùn)行結(jié)果:
1565****165
1390****175
1564****563
1897****454
2.6 re.compile
使用 compile() 函數(shù)將正則表達(dá)式的字符串形式編譯為一個(gè) Pattern 對(duì)象。通過(guò)該對(duì)象提供的一系列方法對(duì)文本進(jìn)行匹配查找,獲得匹配結(jié)果(Match對(duì)象)。編譯可以實(shí)現(xiàn)更高效的匹配查找等。
compile()函數(shù)
compile() 函數(shù)用于編譯正則表達(dá)式,生成一個(gè) Pattern 對(duì)象,它的一般使用形式如下:
import re
# 將正則表達(dá)式編譯成 Pattern 對(duì)象
pattern_1 = re.compile('\d+', re.S)
pattern_2 = re.compile('\D+', re.l)
pattern_3 = re.compile('\w+', re.S)
之前定義pattern都是不包括flags參數(shù)的,因此不用re.compile,僅用賦值語(yǔ)句讓pattern = ‘\d+’也能實(shí)現(xiàn),compile函數(shù)的優(yōu)點(diǎn)在于:1.可以包含flags參數(shù);2.形成模塊,便于后續(xù)復(fù)用
results1 = re.findall(pattern_1, '540775360@qq.com')
results2 = re.findall(pattern_2, "python = 9999, c = 7890, c++ = 12345")
results3 = re.findall(pattern_3, "python = 997")
print(results1, results2, results3)
2.7 原生字符串
>>> mm = "c:\\a\\b\\c"
>>> mm
'c:\\a\\b\\c'
>>> print(mm)
c:\a\b\c
>>> re.match("c:\\\\",mm).group()
'c:\\'
>>> ret = re.match("c:\\\\",mm).group()
>>> print(ret)
c:\
>>> ret = re.match("c:\\\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\\a",mm).group()
>>> print(ret)
c:\a
>>> ret = re.match(r"c:\a",mm).group()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'NoneType' object has no attribute 'group'
>>>鄭州做流產(chǎn)多少錢(qián) http://www.kdwtrl.com/
Python中字符串前面加上 r 表示原生字符串,
與大多數(shù)編程語(yǔ)言相同,正則表達(dá)式里使用"\"作為轉(zhuǎn)義字符,這就可能造成反斜杠困擾。假如你需要匹配文本中的字符"\\",那么使用編程語(yǔ)言表示的正則表達(dá)式里將需要4個(gè)反斜杠"\":前兩個(gè)和后兩個(gè)分別用于在編程語(yǔ)言里轉(zhuǎn)義成反斜杠,轉(zhuǎn)換成兩個(gè)反斜杠后再在正則表達(dá)式里轉(zhuǎn)義成一個(gè)反斜杠。
Python里的原生字符串很好地解決了這個(gè)問(wèn)題,有了原生字符串,你再也不用擔(dān)心是不是漏寫(xiě)了反斜杠,寫(xiě)出來(lái)的表達(dá)式也更直觀(guān)。
>>> ret = re.match(r"c:\\a",mm).group()
>>> print(ret)
c:\a
2.8 匹配開(kāi)頭結(jié)尾
字符 功能
^ 匹配字符串開(kāi)頭
$ 匹配字符串結(jié)尾
末尾匹配
需求:匹配163.com的郵箱地址
#coding=utf-8
import re
email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
for email in email_list:
ret = re.match("[\w]{4,20}@163\.com", email)
if ret:
print("%s 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:%s" % (email, ret.group()))
else:
print("%s 不符合要求" % email)
運(yùn)行結(jié)果:
xiaoWang@163.com 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com
xiaoWang@163.comheihei 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com
.com.xiaowang@qq.com 不符合要求
完善后
email_list = ["xiaoWang@163.com", "xiaoWang@163.comheihei", ".com.xiaowang@qq.com"]
for email in email_list:
ret = re.match("[\w]{4,20}@163\.com$", email)
if ret:
print("%s 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:%s" % (email, ret.group()))
else:
print("%s 不符合要求" % email)
運(yùn)行結(jié)果:
xiaoWang@163.com 是符合規(guī)定的郵件地址,匹配后的結(jié)果是:xiaoWang@163.com
xiaoWang@163.comheihei 不符合要求
.com.xiaowang@qq.com 不符合要求
這個(gè)例子只用于展示,用來(lái)匹配郵箱是沒(méi)有意義的。因?yàn)樗ヅ洳怀瞿┪膊皇莄om但包含了郵箱信息的多行字符串,如
'''
xiaoWang@163.com
xiaoKang@163.com
以上就是郵箱
'''
萬(wàn)能正則
(.*?) 匹配除了換行以外的任意字符串。無(wú)論長(zhǎng)短,最多匹配一次,非貪婪匹配。
這個(gè)正則表達(dá)式可以解決你想要提取的大部分?jǐn)?shù)據(jù),在寫(xiě)正則表達(dá)式的時(shí)候可以首先嘗試這個(gè)組合,也許能達(dá)到事半功倍的效果。并且常常結(jié)合re.findall()函數(shù)。
2.9 案例:抓取電影天堂數(shù)據(jù)
'''
電影天堂思路:
1. 進(jìn)入最新的電影更多 --> 更多的第一頁(yè)
2. 翻頁(yè) https://www.dytt8.net/html/gndy/dyzz/list_23_{}.html
1. > 提取每一頁(yè)的數(shù)據(jù)電影的詳情頁(yè)網(wǎng)址
2. > 發(fā)送請(qǐng)求 得到響應(yīng)
3. > 正則提取鏈接
4. > 保存數(shù)據(jù)(文件)
抓取之前盡量熟悉網(wǎng)頁(yè)的布局和結(jié)構(gòu)!! 熟悉網(wǎng)址的關(guān)系, 經(jīng)常查找網(wǎng)頁(yè)源碼中的數(shù)據(jù)(Ctrl+F).
'''
import re
import requests
for page in range(1, 5):
url_list = f'https://www.dytt8.net/html/gndy/dyzz/list_23_{page}.html'
# 找到詳情頁(yè)的網(wǎng)址 先進(jìn)入 列表頁(yè)
r_list = requests.get(url_list)
# 指定編碼
r_list.encoding = 'gb2312'
# 提取詳情頁(yè)的網(wǎng)址 返回列表
url_detail = re.findall('', r_list.text)
for u in url_detail:
url = 'https://www.dytt8.net' + u
# print(url)
# 再次發(fā)請(qǐng)求 得到詳情頁(yè)的響應(yīng)
response = requests.get(url)
# 也會(huì)亂碼
response.encoding = 'gb2312'
# 提取數(shù)據(jù)
result = re.findall('.*?', response.text)[0:]
print(result)
try:
with open('dytt.txt', 'a', encoding='utf-8') as fp:
# write 只能字符串 和 二進(jìn)制的 不能寫(xiě)字典 列表 等
fp.write(result[0]+'\n')
except:
print('沒(méi)有提取到數(shù)據(jù)!!')
'''
歌曲下載:
可見(jiàn)即可爬 電影(VIP) 歌曲
思路:
1. 抓包 找到翻頁(yè) http://www.htqyy.com/genre/musicList/3?pageIndex=6&pageSize=20&order=hot
2. 進(jìn)入上面的網(wǎng)址 提取歌曲id
3. 下載歌曲 http://f2.htqyy.com/play7/{id}/mp3/1
'''
import re
import requests
for page in range(1, 3): # 1, 2
# 翻頁(yè)的
url_song = f'http://www.htqyy.com/genre/musicList/3?pageIndex={page}&pageSize=20&order=hot'
# 發(fā)送請(qǐng)求得到響應(yīng) 提取響應(yīng)中的歌曲ID
response_song = requests.get(url_song)
# 提取ID 返回列表
id_songs = re.findall('value="(\d+)">
# 遍歷歌曲的id 然后下載
for ids in id_songs:
song_url = 'http://f2.htqyy.com/play7/{}/mp3/1'.format(ids)
try:
# 請(qǐng)求歌曲的網(wǎng)址 然后得到響應(yīng)
response = requests.get(song_url, timeout=5)
# 保存歌曲
with open(f'{ids}.mp3', 'wb') as fp:
fp.write(response.content)
except:
print(f'這個(gè)歌曲{ids}出錯(cuò)')
到此,關(guān)于“怎么理解并掌握python正則表達(dá)式和re模塊”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。