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