<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
我們在做介面自動化的時候,處理介面依賴的相關資料時,通常會使用正規表示式來進行提取相關的資料。
正規表示式,又稱正規表示式、正規表示法、正規表示式、規則表示式、常規表示法(Regular Expression,在程式碼中常簡寫為regex、regexp或RE) 。它是一個特殊的字元序列,它能幫助你方便的檢查一個字串是否與某種模式匹配。在很多文字編輯器裡,正規表示式通常被用來檢索、替換那些匹配某個模式的文字。而Python 自1.5版本起增加了re模組,它提供 Perl 風格的正規表示式模式。
單字元:即表示一個單獨的字元,比如匹配數位用d,匹配非數位用D。
除以下語法,也可以匹配指定的具體字元,可以是1個也可以是多個。
字元 | 功能說明 |
. | 匹配任意1個字元(除了n) |
[2a] | 匹配[]中括號中列舉的字元,如這裡就是匹配2或者a這兩個字元其中的一個 |
d | 匹配數位,即0-9 |
D | 匹配非數位 |
s | 匹配空白,即空格、tab鍵(tab鍵為兩個空格) |
S | 匹配非空白 |
w | 匹配單詞字元,即a-z、A-Z、0-9、_(數位、字母、下劃線) |
W | 匹配非單詞字元 |
範例如下,這裡先說明一下findall(匹配規則,要匹配的字串)這個方法是查詢所有匹配的資料,以列表的形式返回,後面會在re模組進行詳解:
import re # .:匹配任意1個字元 re1 = r'.' res1 = re.findall(re1, 'nj8?0nbthnihb') print(res1) # 執行結果:['j', '8', '?', '0', 'b', 't', 'h', 'i', 'h', 'b'] # []:匹配列舉中的其中一個 re2 = r"[abc]" res2 = re.findall(re2, '1iugfiSHOIFUOFGIDHFGFD2345a6a78b99cc') print(res2) # 執行結果:['a', 'a', 'b', 'c', 'c'] # d:匹配一個數位 re3 = r"d" res3 = re.findall(re3, "dfghjkl32212dfghjk") print(res3) # 執行結果:['3', '2', '2', '1', '2'] # D:匹配一個非數位 re4 = r"D" res4 = re.findall(re4, "d212dk?n$%3;]a") print(res4) # 執行結果:['d', 'd', 'k', '?', 'n', '$', '%', ';', ']', 'a'] # s:匹配一個空白鍵或tab鍵(tab鍵實際就是兩個空白鍵) re5 = r"s" res5 = re.findall(re5,"a s d a 9999") print(res5) # 執行結果:[' ', ' ', ' ', ' ', ' '] # S: 匹配非空白鍵 re6 = r"S" res6 = re.findall(re6, "a s d a 9999") print(res6) # 執行結果:['a', 's', 'd', 'a', '9', '9', '9', '9'] # w:匹配一個單詞字元(數位、字母、下劃線) re7 = r"w" res7 = re.findall(re7, "ce12sd@#a as_#$") print(res7) # 執行結果:['c', 'e', '1', '2', 's', 'd', 'a', 'a', 's', '_'] # W:匹配一個非單詞字元(不是數位、字母、下劃線) re8 = r"W" res8 = re.findall(re8, "ce12sd@#a as_#$") print(res8) # 執行結果:['@', '#', ' ', '#', '$'] # 匹配指定字元 re9 = r"python" res9 = re.findall(re9, "cepy1thon12spython123@@python") print(res9) # 執行結果:['python', 'python']
如果要匹配某個字元多次,就可以在字元后面加上數量進行表示,具體規則如下:
字元 | 功能說明 |
* | 匹配前一個字元出現0次或者無限次,即可有可無 |
+ | 匹配前一個字元出現1次或無限次,即至少1次 |
? | 匹配前一個字元出現0次或1次,即要麼沒有,要麼只有1次 |
{m} | 匹配前一個字元出現m次 |
{m,} | 匹配前一個字元至少出現m次 |
{m,n} | 匹配前一個字元出現從m到n次 |
範例如下:
import re # *:表示前一個字元出現0次以上(包括0次) re21 = r"d*" # 這裡匹配的規則,前一個字元是數位 res21 = re.findall(re21, "343aa1112df345g1h6699") # 如匹配到a時,屬於符合0次,但因為沒有值所以會為空 print(res21) # 執行結果:['343', '', '', '1112', '', '', '345', '', '1', '', '6699', ''] # ? : 表示0次或者一次 re22 = r"d?" res22 = re.findall(re22, "3@43*a111") print(res22) # 執行結果:['3', '', '4', '3', '', '', '1', '1', '1', ''] # {m}:表示匹配一個字元m次 re23 = r"1[3456789]d{9}" # 手機號:第1位為1,第2位匹配列舉的其中1個數位,第3位開始是數位,且匹配9次 res23 = re.findall(re23,"sas13566778899fgh256912345678jkghj12788990000aaa113588889999") print(res23) # 執行結果:['13566778899', '13588889999'] # {m,}:表示匹配一個字元至少m次 re24 = r"d{7,}" res24 = re.findall(re24, "sas12356fgh1234567jkghj12788990000aaa113588889999") print(res24) # 執行結果:['1234567', '12788990000', '113588889999'] # {m,n}:表示匹配一個字元出現m次到n次 re25 = r"d{3,5}" res25 = re.findall(re25, "aaaaa123456ghj333yyy77iii88jj909768876") print(res25) # 執行結果:['12345', '333', '90976', '8876']
字元 | 功能說明 |
| | 匹配左右任意一個表示式 |
(ab) | 將括號中字元作為一個分組 |
範例如下:
import re # 同時定義多個規則,只要滿足其中一個 re31 = r"13566778899|13534563456|14788990000" res31 = re.findall(re31, "sas13566778899fgh13534563456jkghj14788990000") print(res31) # 執行結果:['13566778899', '13534563456', '14788990000'] # ():匹配分組:在匹配規則的資料中提取括號裡的資料 re32 = r"aa(d{3})bb" # 如何資料符合規則,結果只會取括號中的資料,即d{3} res32 = re.findall(re32, "ggghjkaa123bbhhaa672bbjhjjaa@45bb") print(res32) # 執行結果:['123', '672']
字元 | 功能說明 |
^ | 匹配字串開頭,只能匹配開頭 |
$ | 匹配字串結尾,只能匹配結尾 |
b | 匹配一個單詞的邊界(單詞:字母、數位、下劃線) |
B | 匹配非單詞的邊界 |
範例如下:
import re # ^:匹配字串的開頭 re41 = r"^python" # 字串開頭為python res41 = re.findall(re41, "python999python") # 只會匹配這個字串的開頭 res411 = re.findall(re41, "1python999python") # 因為開頭是1,第1位就不符合了 print(res41) # 執行結果:['python'] print(res411) # 執行結果:[] # $:匹配字串的結尾 re42=r"python$" # 字串以python結尾 res42 = re.findall(re42, "python999python") print(res42) # 執行結果:['python'] # b:匹配單詞的邊界,單詞即:字母、數位、下劃線 re43 = r"bpython" # 即匹配python,且python的前一位是不是單詞 res43 = re.findall(re43, "1python 999 python") # 這裡第1個python的前1位是單詞,因此第1個是不符合的 print(res43) # 執行結果:['python'] # B:匹配非單詞的邊界 re44 = r"Bpython" # 即匹配python,且python的前一位是單詞 res44 = re.findall(re44, "1python999python") print(res44) # 執行結果:['python', 'python']
python裡數量詞預設是貪婪的,總是嘗試匹配儘可能多的字元,而非貪婪模式則是嘗試匹配儘可能少的字元,在表示數量的表示式後加上問號(?)就可以關閉貪婪模式。
如下例子,匹配2個以上的數位,如果符合條件它會一直匹配到不符合才停止,如其中的34656fya,34656符合2個數位以上,那麼它會一直匹配到6為止,如果關閉貪婪模式,那麼在滿足2個數位時就會停止,最後可以匹配到34、65。
import re # 預設的貪婪模式下 test = 'aa123aaaa34656fyaa12a123d' res = re.findall(r'd{2,}', test) print(res) # 執行結果:['123', '34656', '12', '123'] # 關閉貪婪模式 res2 = re.findall(r'd{2,}?', test) print(res2) # 執行結果:['12', '34', '65', '12', '12']
在python中使用正規表示式,就會用到re模組來進行操作,提供的方法一般需要傳入兩個引數:
查詢所有符合規範的字串,以列表的形式返回。
import re test = 'aa123aaaa34656fyaa12a123d' res = re.findall(r'd{2,}', test) print(res) # 執行結果:['123', '34656', '12', '123']
查詢第一個符合規範的字串,返回的是一個匹配物件,可以通過group()將匹配到的資料直接提取出來。
import re s = "123abc123aaa123bbb888ccc" res2 = re.search(r'123', s) print(res2) # 執行結果:<re.Match object; span=(0, 3), match='123'> # 通過group將匹配到的資料提取出來,返回型別為str print(res2.group()) # 執行結果:123
返回的匹配物件中,span為匹配到的資料的下標範圍,match則是匹配到的值。
group()引數說明:
import re s = "123abc123aaa123bbb888ccc" re4 = r"aaa(d{3})bbb(d{3})ccc" # 這裡分組就是前面說到的匹配語法:() res4 = re.search(re4, s) print(res4) # group不傳引數:獲取的是匹配到的所有內容 # group通過引數指定,獲取第幾個分組中的內容(獲取第1個分組,傳入引數1,獲取第2個分組,傳入引數2,依次類推.. print(res4.group()) print(res4.group(1)) print(res4.group(2))
從字串的起始位置進行匹配,匹配成功則返回匹配到的物件,如果開頭的位置不符合匹配的規則,不會繼續往後面去匹配,直接返回None。re.match()與re.search()都是隻匹配一個,不一樣的是,前者只匹配字串的開頭,後者則是會匹配整個字串,但只獲取第一個符合的資料。
import re s = "a123abc123aaa1234bbb888ccc" # match:只匹配字串的開頭,開頭不符合就返回None res1 = re.match(r"a123", s) res2 = re.match(r"a1234", s) print(res1) # 執行結果:<re.Match object; span=(0, 4), match='a123'> print(res2) # 執行結果:None
檢索和替換:用於替換字串中的匹配項
re.sub()引數說明:
import re s = "a123abc123aaa123bbb888ccc" # <font color="#FF0000">引數1:</font>待替換的字串 # <font color="#FF0000">引數2:</font>目標字串 # <font color="#FF0000">引數3:</font>要進行替換操作的字串 # <font color="#FF0000">引數4:</font>可以指定最多替換的次數,非必填(預設替換所有符合規範的字串) res5 = re.sub(r'123', "666", s, 4) print(res5) # 執行結果:a666abc666aaa666bbb888ccc
在介面自動化測試中,我們的測試資料都是儲存在excel中的,有些引數如果寫死一個資料,可能換個場景或者換個環境就不能用了,那麼切換環境時就需要先把新環境的測試資料準備好,並且能支援去跑我們的指令碼,或者把excel的資料修改為適合新環境的測試資料,維護的成本較高。因此就需要把我們的自動化指令碼測試資料儘量地引數化,降低維護成本。
我們先看簡單版的引數化,以登入為例,登入時用到的賬號、密碼等資訊都可以提取出來放到組態檔,修改資料或更換環境時直接在組態檔中統一修改就可以了。
但如果有多個不同的資料需要引數化呢,每個引數都加個判斷去替換資料嗎?這樣的程式碼既囉嗦又不好維護,這時re模組就可以用上了,直接看一個範例:
import re from common.myconfig import conf class TestData: """用於臨時儲存一些要替換的資料""" pass def replace_data(data): r = r"#(.+?)#" # 注意這個分組()內的內容 # 判斷是否有需要替換的資料 while re.search(r, data): res = re.search(r, data) # 匹配出第一個要替換的資料 item = res.group() # 提取要替換的資料內容 key = res.group(1) # 獲取要替換內容中的資料項 try: # 根據替換內容中的資料項去組態檔中找到對應的內容,進行替換 data = data.replace(item, conf.get_str("test_data", key)) except: # 如果在組態檔中找不到就在臨時儲存的資料中找,然後替換 data = data.replace(item, getattr(TestData, key)) return data
注意這裡的正規表示式是有使用?關閉貪婪模式的,因為測試資料中可能會需要引數化2個或以上的資料,如果不關閉貪婪模式,它就只能匹配搭配一個資料,舉例如下:
import re data = '{"mobile_phone":"#phone#","pwd":"#pwd#","user":#user#}' r1 = "#(.+)#" res1 = re.findall(r1, data) print(res1) # 執行結果:['phone#","pwd":"#pwd#","user":#user'] 注意這裡單引號只有一個資料 print(len(res1)) # 執行結果:1 r2 = "#(.+?)#" res2 = re.findall(r2, data) print(res2) # 執行結果:['phone', 'pwd', 'user'] print(len(res2)) # 執行結果:3
另外提到的一個用於臨時儲存資料的類,這裡主要用於儲存介面返回的資料,因為有些測試資料是動態變化的,可能要依賴於某個介面,後面的測試用例又需要這些資料,那麼我們在介面返回時就可以儲存到這個類裡作為一個類屬性,接著在需要用這個資料的測試用例時,把這個類屬性提取出來替換到測試資料中即可。提示:設定屬性setattr(物件, 屬性名, 屬性值),獲取屬性值getattr(物件, 屬性名)。
到此這篇關於python介面自動化之正則用例引數化的文章就介紹到這了,更多相關python正則用例引數化內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45