網(wǎng)站首頁 編程語言 正文
前言
?我們在做接口自動化的時候,處理接口依賴的相關(guān)數(shù)據(jù)時,通常會使用正則表達(dá)式來進(jìn)行提取相關(guān)的數(shù)據(jù)。
?正則表達(dá)式,又稱正規(guī)表示式、正規(guī)表示法、正規(guī)表達(dá)式、規(guī)則表達(dá)式、常規(guī)表示法(Regular Expression,在代碼中常簡寫為regex、regexp或RE) 。它是一個特殊的字符序列,它能幫助你方便的檢查一個字符串是否與某種模式匹配。在很多文本編輯器里,正則表達(dá)式通常被用來檢索、替換那些匹配某個模式的文本。而Python 自1.5版本起增加了re模塊,它提供 Perl 風(fēng)格的正則表達(dá)式模式。
一、正則表達(dá)式語法
1.1表示單字符
?單字符:即表示一個單獨(dú)的字符,比如匹配數(shù)字用\d,匹配非數(shù)字用\D。
?除以下語法,也可以匹配指定的具體字符,可以是1個也可以是多個。
字符 |
功能說明 |
. |
匹配任意1個字符(除了\n) |
[2a] |
匹配[]中括號中列舉的字符,如這里就是匹配2或者a這兩個字符其中的一個 |
\d |
匹配數(shù)字,即0-9 |
\D |
匹配非數(shù)字 |
\s |
匹配空白,即空格、tab鍵(tab鍵為兩個空格) |
\S |
匹配非空白 |
\w |
匹配單詞字符,即a-z、A-Z、0-9、_(數(shù)字、字母、下劃線) |
\W |
匹配非單詞字符 |
?實(shí)例如下,這里先說明一下findall(匹配規(guī)則,要匹配的字符串)這個方法是查找所有匹配的數(shù)據(jù),以列表的形式返回,后面會在re模塊進(jìn)行詳解:
import re
# .:匹配任意1個字符
re1 = r'.'
res1 = re.findall(re1, '\nj8?0\nbth\nihb')
print(res1) # 運(yùn)行結(jié)果:['j', '8', '?', '0', 'b', 't', 'h', 'i', 'h', 'b']
# []:匹配列舉中的其中一個
re2 = r"[abc]"
res2 = re.findall(re2, '1iugfiSHOIFUOFGIDHFGFD2345a6a78b99cc')
print(res2) # 運(yùn)行結(jié)果:['a', 'a', 'b', 'c', 'c']
# \d:匹配一個數(shù)字
re3 = r"\d"
res3 = re.findall(re3, "dfghjkl32212dfghjk")
print(res3) # 運(yùn)行結(jié)果:['3', '2', '2', '1', '2']
# \D:匹配一個非數(shù)字
re4 = r"\D"
res4 = re.findall(re4, "d212dk?\n$%3;]a")
print(res4) # 運(yùn)行結(jié)果:['d', 'd', 'k', '?', '\n', '$', '%', ';', ']', 'a']
# \s:匹配一個空白鍵或tab鍵(tab鍵實(shí)際就是兩個空白鍵)
re5 = r"\s"
res5 = re.findall(re5,"a s d a 9999")
print(res5) # 運(yùn)行結(jié)果:[' ', ' ', ' ', ' ', ' ']
# \S: 匹配非空白鍵
re6 = r"\S"
res6 = re.findall(re6, "a s d a 9999")
print(res6) # 運(yùn)行結(jié)果:['a', 's', 'd', 'a', '9', '9', '9', '9']
# \w:匹配一個單詞字符(數(shù)字、字母、下劃線)
re7 = r"\w"
res7 = re.findall(re7, "ce12sd@#a as_#$")
print(res7) # 運(yùn)行結(jié)果:['c', 'e', '1', '2', 's', 'd', 'a', 'a', 's', '_']
# \W:匹配一個非單詞字符(不是數(shù)字、字母、下劃線)
re8 = r"\W"
res8 = re.findall(re8, "ce12sd@#a as_#$")
print(res8) # 運(yùn)行結(jié)果:['@', '#', ' ', '#', '$']
# 匹配指定字符
re9 = r"python"
res9 = re.findall(re9, "cepy1thon12spython123@@python")
print(res9) # 運(yùn)行結(jié)果:['python', 'python']
1.2表示數(shù)量
?如果要匹配某個字符多次,就可以在字符后面加上數(shù)量進(jìn)行表示,具體規(guī)則如下:
字符 |
功能說明 |
* |
匹配前一個字符出現(xiàn)0次或者無限次,即可有可無 |
+ |
匹配前一個字符出現(xiàn)1次或無限次,即至少1次 |
? |
匹配前一個字符出現(xiàn)0次或1次,即要么沒有,要么只有1次 |
{m} |
匹配前一個字符出現(xiàn)m次 |
{m,} |
匹配前一個字符至少出現(xiàn)m次 |
{m,n} |
匹配前一個字符出現(xiàn)從m到n次 |
?實(shí)例如下:
import re
# *:表示前一個字符出現(xiàn)0次以上(包括0次)
re21 = r"\d*" # 這里匹配的規(guī)則,前一個字符是數(shù)字
res21 = re.findall(re21, "343aa1112df345g1h6699") # 如匹配到a時,屬于符合0次,但因?yàn)闆]有值所以會為空
print(res21) # 運(yùn)行結(jié)果:['343', '', '', '1112', '', '', '345', '', '1', '', '6699', '']
# ? : 表示0次或者一次
re22 = r"\d?"
res22 = re.findall(re22, "3@43*a111")
print(res22) # 運(yùn)行結(jié)果:['3', '', '4', '3', '', '', '1', '1', '1', '']
# {m}:表示匹配一個字符m次
re23 = r"1[3456789]\d{9}" # 手機(jī)號:第1位為1,第2位匹配列舉的其中1個數(shù)字,第3位開始是數(shù)字,且匹配9次
res23 = re.findall(re23,"sas13566778899fgh256912345678jkghj12788990000aaa113588889999")
print(res23) # 運(yùn)行結(jié)果:['13566778899', '13588889999']
# {m,}:表示匹配一個字符至少m次
re24 = r"\d{7,}"
res24 = re.findall(re24, "sas12356fgh1234567jkghj12788990000aaa113588889999")
print(res24) # 運(yùn)行結(jié)果:['1234567', '12788990000', '113588889999']
# {m,n}:表示匹配一個字符出現(xiàn)m次到n次
re25 = r"\d{3,5}"
res25 = re.findall(re25, "aaaaa123456ghj333yyy77iii88jj909768876")
print(res25) # 運(yùn)行結(jié)果:['12345', '333', '90976', '8876']
1.2.1匹配分組
字符 |
功能說明 |
| |
匹配左右任意一個表達(dá)式 |
(ab) |
將括號中字符作為一個分組 |
? 實(shí)例如下:
import re
# 同時定義多個規(guī)則,只要滿足其中一個
re31 = r"13566778899|13534563456|14788990000"
res31 = re.findall(re31, "sas13566778899fgh13534563456jkghj14788990000")
print(res31) # 運(yùn)行結(jié)果:['13566778899', '13534563456', '14788990000']
# ():匹配分組:在匹配規(guī)則的數(shù)據(jù)中提取括號里的數(shù)據(jù)
re32 = r"aa(\d{3})bb" # 如何數(shù)據(jù)符合規(guī)則,結(jié)果只會取括號中的數(shù)據(jù),即\d{3}
res32 = re.findall(re32, "ggghjkaa123bbhhaa672bbjhjjaa@45bb")
print(res32) # 運(yùn)行結(jié)果:['123', '672']
1.3 表示邊界
字符 |
功能說明 |
^ |
匹配字符串開頭,只能匹配開頭 |
$ |
匹配字符串結(jié)尾,只能匹配結(jié)尾 |
\b |
匹配一個單詞的邊界(單詞:字母、數(shù)字、下劃線) |
\B |
匹配非單詞的邊界 |
?實(shí)例如下:
import re
# ^:匹配字符串的開頭
re41 = r"^python" # 字符串開頭為python
res41 = re.findall(re41, "python999python") # 只會匹配這個字符串的開頭
res411 = re.findall(re41, "1python999python") # 因?yàn)殚_頭是1,第1位就不符合了
print(res41) # 運(yùn)行結(jié)果:['python']
print(res411) # 運(yùn)行結(jié)果:[]
# $:匹配字符串的結(jié)尾
re42=r"python$" # 字符串以python結(jié)尾
res42 = re.findall(re42, "python999python")
print(res42) # 運(yùn)行結(jié)果:['python']
# \b:匹配單詞的邊界,單詞即:字母、數(shù)字、下劃線
re43 = r"\bpython" # 即匹配python,且python的前一位是不是單詞
res43 = re.findall(re43, "1python 999 python") # 這里第1個python的前1位是單詞,因此第1個是不符合的
print(res43) # 運(yùn)行結(jié)果:['python']
# \B:匹配非單詞的邊界
re44 = r"\Bpython" # 即匹配python,且python的前一位是單詞
res44 = re.findall(re44, "1python999python")
print(res44) # 運(yùn)行結(jié)果:['python', 'python']
二、貪婪模式
?python里數(shù)量詞默認(rèn)是貪婪的,總是嘗試匹配盡可能多的字符,而非貪婪模式則是嘗試匹配盡可能少的字符,在表示數(shù)量的表達(dá)式后加上問號(?)就可以關(guān)閉貪婪模式。
? 如下例子,匹配2個以上的數(shù)字,如果符合條件它會一直匹配到不符合才停止,如其中的34656fya,34656符合2個數(shù)字以上,那么它會一直匹配到6為止,如果關(guān)閉貪婪模式,那么在滿足2個數(shù)字時就會停止,最后可以匹配到34、65。
import re
# 默認(rèn)的貪婪模式下
test = 'aa123aaaa34656fyaa12a123d'
res = re.findall(r'\d{2,}', test)
print(res) # 運(yùn)行結(jié)果:['123', '34656', '12', '123']
# 關(guān)閉貪婪模式
res2 = re.findall(r'\d{2,}?', test)
print(res2) # 運(yùn)行結(jié)果:['12', '34', '65', '12', '12']
三、re模塊
?在python中使用正則表達(dá)式,就會用到re模塊來進(jìn)行操作,提供的方法一般需要傳入兩個參數(shù):
- 參數(shù)1: 匹配的規(guī)則
- 參數(shù)2:要進(jìn)行匹配的字符串
3.1 re.findall()
?查找所有符合規(guī)范的字符串,以列表的形式返回。
import re
test = 'aa123aaaa34656fyaa12a123d'
res = re.findall(r'\d{2,}', test)
print(res) # 運(yùn)行結(jié)果:['123', '34656', '12', '123']
3.2re.search()
?查找第一個符合規(guī)范的字符串,返回的是一個匹配對象,可以通過group()將匹配到的數(shù)據(jù)直接提取出來。
import re
s = "123abc123aaa123bbb888ccc"
res2 = re.search(r'123', s)
print(res2) # 運(yùn)行結(jié)果:<re.Match object; span=(0, 3), match='123'>
# 通過group將匹配到的數(shù)據(jù)提取出來,返回類型為str
print(res2.group()) # 運(yùn)行結(jié)果:123
?返回的匹配對象中,span為匹配到的數(shù)據(jù)的下標(biāo)范圍,match則是匹配到的值。
?group()參數(shù)說明:
- 不傳參數(shù):獲取的是匹配到的所有內(nèi)容
- 傳入數(shù)值:可以通過參數(shù)來指定,獲取第幾個分組中的內(nèi)容(獲取第1個分組,傳入?yún)?shù)1,獲取第2個分組,傳入?yún)?shù)2,依次類推。)
import re
s = "123abc123aaa123bbb888ccc"
re4 = r"aaa(\d{3})bbb(\d{3})ccc" # 這里分組就是前面說到的匹配語法:()
res4 = re.search(re4, s)
print(res4)
# group不傳參數(shù):獲取的是匹配到的所有內(nèi)容
# group通過參數(shù)指定,獲取第幾個分組中的內(nèi)容(獲取第1個分組,傳入?yún)?shù)1,獲取第2個分組,傳入?yún)?shù)2,依次類推..
print(res4.group())
print(res4.group(1))
print(res4.group(2))
3.3 re.match()
?從字符串的起始位置進(jìn)行匹配,匹配成功則返回匹配到的對象,如果開頭的位置不符合匹配的規(guī)則,不會繼續(xù)往后面去匹配,直接返回None。re.match()與re.search()都是只匹配一個,不一樣的是,前者只匹配字符串的開頭,后者則是會匹配整個字符串,但只獲取第一個符合的數(shù)據(jù)。
import re
s = "a123abc123aaa1234bbb888ccc"
# match:只匹配字符串的開頭,開頭不符合就返回None
res1 = re.match(r"a123", s)
res2 = re.match(r"a1234", s)
print(res1) # 運(yùn)行結(jié)果:<re.Match object; span=(0, 4), match='a123'>
print(res2) # 運(yùn)行結(jié)果:None
3.4re.sub()
?檢索和替換:用于替換字符串中的匹配項(xiàng)
?re.sub()參數(shù)說明:
- 參數(shù)1:待替換的字符串
- 參數(shù)2:目標(biāo)字符串
- 參數(shù)3:要進(jìn)行替換操作的字符串
- 參數(shù)4:可以指定最多替換的次數(shù),非必填(默認(rèn)替換所有符合規(guī)范的字符串)
import re
s = "a123abc123aaa123bbb888ccc"
# <font color="#FF0000">參數(shù)1:</font>待替換的字符串
# <font color="#FF0000">參數(shù)2:</font>目標(biāo)字符串
# <font color="#FF0000">參數(shù)3:</font>要進(jìn)行替換操作的字符串
# <font color="#FF0000">參數(shù)4:</font>可以指定最多替換的次數(shù),非必填(默認(rèn)替換所有符合規(guī)范的字符串)
res5 = re.sub(r'123', "666", s, 4)
print(res5) # 運(yùn)行結(jié)果:a666abc666aaa666bbb888ccc
四、用例參數(shù)化
?在接口自動化測試中,我們的測試數(shù)據(jù)都是保存在excel中的,有些參數(shù)如果寫死一個數(shù)據(jù),可能換個場景或者換個環(huán)境就不能用了,那么切換環(huán)境時就需要先把新環(huán)境的測試數(shù)據(jù)準(zhǔn)備好,并且能支持去跑我們的腳本,或者把excel的數(shù)據(jù)修改為適合新環(huán)境的測試數(shù)據(jù),維護(hù)的成本較高。因此就需要把我們的自動化腳本測試數(shù)據(jù)盡量地參數(shù)化,降低維護(hù)成本。
我們先看簡單版的參數(shù)化,以登錄為例,登錄時用到的賬號、密碼等信息都可以提取出來放到配置文件,修改數(shù)據(jù)或更換環(huán)境時直接在配置文件中統(tǒng)一修改就可以了。
?但如果有多個不同的數(shù)據(jù)需要參數(shù)化呢,每個參數(shù)都加個判斷去替換數(shù)據(jù)嗎?這樣的代碼既啰嗦又不好維護(hù),這時re模塊就可以用上了,直接看一個實(shí)例:
import re
from common.myconfig import conf
class TestData:
"""用于臨時保存一些要替換的數(shù)據(jù)"""
pass
def replace_data(data):
r = r"#(.+?)#" # 注意這個分組()內(nèi)的內(nèi)容
# 判斷是否有需要替換的數(shù)據(jù)
while re.search(r, data):
res = re.search(r, data) # 匹配出第一個要替換的數(shù)據(jù)
item = res.group() # 提取要替換的數(shù)據(jù)內(nèi)容
key = res.group(1) # 獲取要替換內(nèi)容中的數(shù)據(jù)項(xiàng)
try:
# 根據(jù)替換內(nèi)容中的數(shù)據(jù)項(xiàng)去配置文件中找到對應(yīng)的內(nèi)容,進(jìn)行替換
data = data.replace(item, conf.get_str("test_data", key))
except:
# 如果在配置文件中找不到就在臨時保存的數(shù)據(jù)中找,然后替換
data = data.replace(item, getattr(TestData, key))
return data
?注意這里的正則表達(dá)式是有使用?關(guān)閉貪婪模式的,因?yàn)闇y試數(shù)據(jù)中可能會需要參數(shù)化2個或以上的數(shù)據(jù),如果不關(guān)閉貪婪模式,它就只能匹配搭配一個數(shù)據(jù),舉例如下:
import re
data = '{"mobile_phone":"#phone#","pwd":"#pwd#","user":#user#}'
r1 = "#(.+)#"
res1 = re.findall(r1, data)
print(res1) # 運(yùn)行結(jié)果:['phone#","pwd":"#pwd#","user":#user'] 注意這里單引號只有一個數(shù)據(jù)
print(len(res1)) # 運(yùn)行結(jié)果:1
r2 = "#(.+?)#"
res2 = re.findall(r2, data)
print(res2) # 運(yùn)行結(jié)果:['phone', 'pwd', 'user']
print(len(res2)) # 運(yùn)行結(jié)果:3
?另外提到的一個用于臨時保存數(shù)據(jù)的類,這里主要用于保存接口返回的數(shù)據(jù),因?yàn)橛行y試數(shù)據(jù)是動態(tài)變化的,可能要依賴于某個接口,后面的測試用例又需要這些數(shù)據(jù),那么我們在接口返回時就可以保存到這個類里作為一個類屬性,接著在需要用這個數(shù)據(jù)的測試用例時,把這個類屬性提取出來替換到測試數(shù)據(jù)中即可。提示:設(shè)置屬性setattr(對象, 屬性名, 屬性值),獲取屬性值getattr(對象, 屬性名)。
總結(jié)
原文鏈接:https://blog.csdn.net/ifling99/article/details/125730708
相關(guān)推薦
- 2022-03-16 Redis在項(xiàng)目中的使用(JedisPool方式)_Redis
- 2022-12-23 Kubernetes應(yīng)用服務(wù)質(zhì)量管理詳解_云其它
- 2022-10-15 Go?編程復(fù)雜數(shù)據(jù)類型?Map_Golang
- 2022-05-27 python使用pandas進(jìn)行量化回測_python
- 2022-05-20 SpringCloud系列:springboot改造集成nacos
- 2022-07-14 超詳細(xì)講解C++的三種函數(shù)傳遞方式_C 語言
- 2022-09-08 Pandas如何將Timestamp轉(zhuǎn)為datetime類型_python
- 2022-06-17 C#中Parallel類For、ForEach和Invoke使用介紹_C#教程
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支