前沿拓展:
c 正則表達式
prce著名開源正則庫源碼C包括phpperlpython等語言都直接或間接使用該庫
pcre *re 指向整庫下載
頭文件詳解要看文檔學(xué)習(xí)調(diào)用和使用該庫
文檔都寫著
另外庫開發(fā)者準(zhǔn)備正則間件嵌入程序使程序能解析正則
專正則初學(xué)者練習(xí)正則而設(shè)置學(xué)習(xí)文檔會少
需要熟練整c庫**作流程和常用原理直接去看源碼
提起正則表達式,可能大家的第一印象是:既強大好用但也晦澀難懂。正則表達式在文本處理中相當(dāng)重要,各大編程語言中均有支持(跟 Linux 三劍客結(jié)合更是神兵利器)。正則表達式是對字符串**作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規(guī)則字符串”,這個“規(guī)則字符串”用來表達對字符串的一種過濾邏輯。(來自百度百科)
個人理解如下:某個大佬為了從字符串中匹配或找出符合特定規(guī)律(如手機號、身份證號)的子字符串,先定義了一些通用符號來表示字符串中各個類型的元素(如數(shù)字用 d 表示),再將它們組合起來得到了一個模板(如:dd模板就是指代兩個數(shù)字),拿這個模板去字符串中比對,找出符合該模板的子字符串。
由幾個例子去進一步理解,比如現(xiàn)在有一個字符串為:1.test是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它既可以匹配tester中的test,又可以匹配第二個test。正則表達式中的test就代表test這個單詞本身。
2.btestb是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它只能匹配第二個test。因為b具有特殊意義,指代的是單詞的開頭或結(jié)尾。故tester中的test就不符合該模式。
3.testw*是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它匹配出了tester,也匹配出了第二個test。其中w的意思是匹配字母數(shù)字下劃線,表示的是數(shù)量,指有0個或多個w。所以這個正則表達是的意思就是匹配開頭為test,后續(xù)跟著0個及以上字母數(shù)字下劃線的子字符串
4.testw+是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它只匹配了tester。因為+與不同,+的意思是1個或多個,所以該正則表達式匹配的是開頭為test,后續(xù)跟著1個及以上字母數(shù)字下劃線的字符串。
通過上述幾個例子,應(yīng)該可以看出正則表達式的工作方式,正則表達式由一般字符和元字符組成,一般字符就是例子中的‘test’,其指代的意思就是字符本身,t匹配的就是字母t;元字符就是例子中有特殊含義的字符,如w, b, *, +等。后續(xù)介紹一些基礎(chǔ)的元字符。元字符有很多,不同元字符有不同的作用,大致可以分為如下幾類。有些元字符專門用來指代字符串中的元素類型,常用的如下:
通過上述表格中的數(shù)據(jù)可以發(fā)現(xiàn),w,d,s都有一個與之相反的元字符(將對應(yīng)字母大寫后就是了)。w匹配所有字母數(shù)字下劃線,那么W就是匹配所有不是字母數(shù)字下劃線的字符。只要記住其中3個,另外3個就很好記了。乍一看這幾個元字符挺簡單的,但是經(jīng)常不用的話保不準(zhǔn)會忘記,此處分享一下我的記憶方法。我把這幾個元字符都當(dāng)作是某一個單詞的縮寫(雖然可能就是某個單詞的縮寫,但是沒有找到準(zhǔn)確的資料去印證):
s是space(空間)的縮寫d是digit(數(shù)字)的縮寫w是word(可以理解成不是傳統(tǒng)意義上的單詞而是代碼中的變量名,變量名可包含的元素就是字母數(shù)字下劃線)的縮寫好了,看到此處你應(yīng)該已經(jīng)熟記了6個元字符了。接下來,n和t平時會經(jīng)常用到,這個肯定比較熟了,最后一個元字符‘.’可以理解它匹配一行中的所有元素,因為遇到換行符后就不再進行匹配了(萬事萬物源于一點)。有些元字符用于表示某種元素的數(shù)量,如d表示一個數(shù)字,當(dāng)你想表示6位數(shù)字怎么辦?當(dāng)然可以dddddd ,但確實太麻煩了,為了簡便就需要一些表示數(shù)量的元字符,上述可以寫成d{6},元字符詳情如下:這幾個元字符還算比較好記。表示0個或多個+表示1個或多個(這個可能會混淆,或許你可以這么記, 表示10=0或多個,+表示1+0=1或多個)?表示0或1個,可以理解成某個人在問你這個類型的元素有還是沒有呀?你回答可能有(1)也可能沒有(0)。剩下的三個只要記住大括號是用來表示數(shù)量,后續(xù)我們還會看到除了{}外,還有[]和()。它們各有各的作用。有些元字符沒有具體的的匹配項,它只是一個抽象的位置概念,它用來表示字符串中的各個位置。一個字符串的位置可以分成:字符串的開頭或結(jié)尾、單詞的開頭或結(jié)尾。如字符串‘I am a tester_.’,I前面是字符串的開頭位置,英文句號后面為字符串的結(jié)尾位置,每一個word(注意此處指的不是傳統(tǒng)意義上的單詞)前后的位置即為單詞的開頭或結(jié)尾,對于‘tester_’來說t前面是單詞開頭,下劃線是單詞結(jié)尾。其中b在前面的例子中有說過,此處可以以這種方式記憶:b是block(塊)的縮寫,即一個單詞是一塊內(nèi)容,b是這一塊的邊界。至于另外兩個元字符,暫時沒找到很好的記憶方法(^一個尖角,小荷才露尖尖角?),但應(yīng)該也不難記。此處有個地方要提及一下,所有表示位置的不會實際占用字符。為了理解可以繼續(xù)看最上面的第二個例子,btestb最終匹配出來了子字符串“test”,而不是“ test ”。大家依據(jù)目前了解的元字符概念,可以思考一下這個正則表達式^d{6,10}$,和d{6,10}的區(qū)別。針對字符串‘12345678‘,第一個和第二個都可以匹配出’12345678‘。但是針對字符串’W12345678‘,只有第二個可以正確匹配出’12345678‘,原因在于第一個正則表達式的意思匹配一個字符串只有6-10個數(shù)字組成,而第二個正則表達式意思是匹配字符串中的6-10個連續(xù)數(shù)字。除了這三個元字符表示位置外,還有零寬斷言、負向零寬斷言也表示位置,后續(xù)會詳細介紹。字符轉(zhuǎn)義的概念大家肯定不陌生,對于, +等有特殊意義的元字符,假如你想匹配5個號應(yīng)該怎么寫,{5}嗎?肯定不是,這樣寫是語法錯誤,應(yīng)該使用將其轉(zhuǎn)義:*{5}。這樣一來*的特殊意義就被給取消了,想要匹配的話,也是一樣,再用一個把特殊意義取消掉就好了。前面列出了部分用于表示意義的元字符,但是可能這幾個元字符覆蓋的都太廣泛了,想要具體的匹配某一類字符。比如就是想匹配abcd這四個字符中的某一個,正則表達式當(dāng)然也是支持的。這時候就需要用到第二種括號,中括號。匹配abcd中的某一個可以寫成[abcd]或者[a-d],意思是匹配一個a-d中的任意字符。相反若匹配非abcd的任意字符,可以寫成[^abcd],意思是匹配一個不是abcd的字符。括號內(nèi)也可以寫入不同類型的元素,如[a-d1-7@],表示的是匹配一個a-d或1-7或@中的任意字符,[^a-d1-7@]則與之相反講完中括號后我們可以看一下小括號(),小括號的意思是分組,即小括號內(nèi)部的所有元字符是一個整體。之前有學(xué)過表示數(shù)量的元字符,但是那個表示的數(shù)量都是針對于一個元字符來說的,比如ab+表示的是匹配一個a后面跟著1個或多個b的子字符串。倘若我們想要匹配的是1個或多個ab(如:abababab),此時分組就派上作用了,可以這么寫:(ab)+。此時ab被綁定為一個整體,后面的數(shù)量元字符對這個整體起作用。元字符中有一個或運算符,它與大多數(shù)編程語言類似都是用 | 來表示。它的作用為:Ab|aB表示的是匹配Ab或者aB。通過這個例子可以很直觀的理解該元字符的作用。當(dāng)然它也經(jīng)常和分組一起使用:(Ab|aB)+c,該正則匹配開始為1-N個Ab或aB之后是c的子字符串,如:AbaBc, AbAbAbaBc。后向引用的使用是依附于分組的,分組的概念之前講過了。第一,我們先看一下正則表達式中組號的分配方式,此時先看一個用到分組的正則表達式:(ab)?(c|C)d。這個正則的意思大家現(xiàn)在肯定都清楚了。這個正則表達式里面用到了兩個分組分別是(ab)和(c|C)。正則內(nèi)部會對所有分組進行組號分配,從左向右,第一個分組(ab)的組號是1,第二個分組(c|C)的組號是2。而組號0代表的是整個正則表達式。嘗試過python正則的此處應(yīng)該有印象,匹配對象的group方法傳參為0或不傳則返回整個正則所匹配的結(jié)果,傳參為1為第一個分組匹配的結(jié)果。了解了組號分配方式后,可以開始解釋后向引用了。后向引用就是將前面某個分組已經(jīng)匹配的數(shù)據(jù)拿過來用,第一個分組匹配的數(shù)據(jù)用1代替,第二個分組匹配的數(shù)據(jù)用2代替,依次類推。似乎不是特別好理解,直接看例子吧,(ab)?(c|C)d2D該正則中2表示的是第二個分組匹配到的數(shù)據(jù),若第二個分組匹配到了c那么2就是c,反之亦然。所以它能匹配到:abcdcD, abCdCD。不能匹配:abcdCD, abCdcD。通過這個例子可以理解它的作用了吧。當(dāng)然分組除了有自己的組號外,還可以給它自定義組名。不同編程語言中的方式不同,Python中自定義組名的格式為:(?Pexp),Name為你自定義的組名,exp代表任意元字符的組合。后面引用的方法為(?P=name)。所以上面例子可以修改成:(ab)?(?Pc|C)d(?P=CWord)D。上一節(jié)簡單的講了一下正則表達式是如何分配組號的,但其實還有幾個需要注意的地方。雖然組號是從左向右進行分配,但是掃描兩遍,第一遍先分配給未命名的分組,第二遍再分配給命名的分組。所以命名后的分組組號會更大使用(?:exp)可以使一個分組不分配組號,如(?:ab)?(c|C)d2D中(ab)就沒有分配到組號,而(c|C)組號為1人性是貪婪的,正則表達式與人一樣也是貪婪的。一個正則表達式會盡量多的去匹配字符串,如:ab.+c去匹配’abccccc’是會將該字符串全部匹配出來。但有時候我們只想要其匹配’abcc’,此時怎么辦呢?需要給正則表達式中表示數(shù)量的元字符加一個?變成ab.+?c。此時該正則表達式就變懶了,不會再去匹配那么多,匹配到‘a(chǎn)bcc’就完事了。這兩個個概念有些不太好理解。正如前面所說這兩個也是表示位置的元字符。從字面意思上理解,零寬代表其沒有寬度,即如之前介紹表示位置的元字符中提到的一樣,不會實際占用字符。斷言是什么?是assert,是用來判斷條件是True還是False。理解完這兩個詞語的意思后,零寬斷言的概念應(yīng)該也就能理解了。那么負向無非就是它的反義詞。上面的表格主要看第一列它是什么格式就好,反正后面的名稱和說明也很難看懂。接下來我來用自己的理解通俗的解釋一下這些概念。第一字符串中可以有四種方式確認(rèn)某個子字符串的位置,如字符串‘BACAB’中有兩個A,A前面是B、A前面不是B、A后面是C、A后面不是C。上述四種條件都能夠匹配出唯一一個子字符串A。這個例子大概理解的話就可以往后看了。(?=exp)中exp指代的是任意元字符的組合,結(jié)合具體的例子來理解該元字符的用法,一個正則表達式為A(?=C),它代表的情況就是A后面是C的情況。所以匹配出了第一個A,由于該元字符是零寬所以它只能匹配出A而不是AC。(?<=exp)與上面用法相反,一個正則表達式為(?<=B)A,它代表的情況就是A前面是B的情況。所以匹配出了第一個A。如果改成(?<=C)A,則能匹配出第二個A。(?!exp)的例子為:A(?!C),它代表的情況為A后面不是C,所以匹配出第二個A。(?<!exp)的例子為:(?<!B)A,它代表的情況為A前面不是B,所以匹配出第二個A。通過上面四個例子的介紹,應(yīng)該對于這兩個概念、四個元字符有了了解。理解是重點,記下來也是重點。本人是這樣記下來的,四個元字符的基本格式都是(?),只不過問號后面的不一樣。分下面兩種情況:XXX前/后是XXX的話就寫一個=,XXX前/后不是XXX的話就寫一個!。這個和日常用的=和!=差不多。如果表示的意思是前的話,這個元字符就需要出現(xiàn)在前面且要加一個類似于向前指的箭頭<。如果表示的意思是后的話,就什么都不需要加。通過上面兩個情況的歸納,是不是這四個元字符就都記下來了?到目前為止,正則表達式的基本內(nèi)容都介紹完了。但是文中用的例子都比較簡單,只能幫助你理解概念。如果感興趣或者工作中能用到的話,還需要后續(xù)勤加練習(xí)。你以為文章到小編綜合來說就結(jié)束了?So naive,我再來列舉一個測試日常工作中的案例,將理論應(yīng)用到實踐(編程語言選擇 Python,因為我目前只會這個)。設(shè)想這么一個場景,在測試過程中需要獲取某個時間段內(nèi)某個程序的運行情況,從而分析出該程序的穩(wěn)定性或使用頻率等指標(biāo),該程序的日志記錄完備,日志格式固定且已知。這時候最佳的辦法就是從該程序日志中進行相關(guān)信息的獲取。假如該日志內(nèi)容格式大概如下(注:該日志樣例不是實際項目中的日志文件,為個人舉例):從這個日志中可以看到訪問成功的IP及其認(rèn)證賬號、訪問失敗的IP、程序的錯誤信息。那么我們怎么把這些數(shù)據(jù)給抓取出來呢?抓取的方法肯定有很多,如果此時你第一時間想到了正則表達式,那么恭喜你,通過閱讀前面的文章,正則已經(jīng)在你心中留下了痕跡,或者它本來就留有痕跡。我們先來分析一下第一條日志,其余的與此類似,有用的信息可以分成如下幾個片段:時間字符串:2020-02-17 11:04:34日志級別:INFOIP:182.168.3.111認(rèn)證郵箱:110232123@qq.com狀態(tài)碼:1客戶端獲取到的數(shù)據(jù)大?。?2931KB上面幾個片段對應(yīng)的正則為:時間字符串:d{4}-d{2}-d{2}s*d{2}:d{2}:d{2}日志級別:[INFO]IP:(d{1,3}.){3}d{1,3}認(rèn)證郵箱:w+@w+.w+狀態(tài)碼:d+客戶端獲取到的數(shù)據(jù)大?。篸+KB上述中某幾個正則其實并不嚴(yán)謹(jǐn),比如IP對應(yīng)的正則還可以匹配出999.999.999.999。嚴(yán)謹(jǐn)?shù)恼齽t表達式是((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)。由于該正則太長,加之此處重點在于如何應(yīng)用,故暫用其寬松版的正則表達式。知道了各個字段的正則后,我們可以將它們各自寫成一個分組,分組之間填充上其余元字符,把匹配整行日志的正則表達式寫出來,如下:現(xiàn)在我們通過這個正則表達式可以抓取出日志文件中這種格式的日志字符串,再根據(jù)組號就可以拿出來對應(yīng)的數(shù)據(jù)了。不過根據(jù)組號取數(shù)據(jù)可能會有些含糊不清,或許我們可以給每個分組進行命名(使用python支持的方式),形成如下正則表達式:好了現(xiàn)在我們可以很清楚的看到,表示時間的分組命名為Time,依次類推。接下來,我們可以使用上述正則表達式去抓取一行日志,再通過分組的名稱拿到對于的字符串?dāng)?shù)據(jù)了。具體的代碼可以參考下面的樣例:代碼中實現(xiàn)了一個函數(shù)reg_deal,后面代碼都是對于這個函數(shù)的實際應(yīng)用,該函數(shù)入?yún)椋赫齽t表達式組成的列表、待匹配的字符串、特殊函數(shù)組成的字典。其先循環(huán)將字符串與列表中各個正則表達式進行匹配,匹配成功后得到一個匹配對象,調(diào)用該匹配對象的groupdict函數(shù)可以返回一個結(jié)果字典,該結(jié)果字典的鍵為分組的名稱,值為分組匹配到的值。針對這一結(jié)果字典再進行一步特殊函數(shù)處理,如上述中的status字段日志中是碼值,但輸出結(jié)果需要是具體的漢字。故對其進行了一步碼值轉(zhuǎn)換**作,對與數(shù)據(jù)大小將KB轉(zhuǎn)化成了MB。若使用該函數(shù),需自己將正則表達式寫出來并對正則表達式中的分組進行命名,若有些分組數(shù)據(jù)需要特殊處理,則維護一個特殊函數(shù)字典,鍵為分組名,值為函數(shù)(匿名函數(shù)或者是函數(shù)名稱)。將參數(shù)傳入后即可獲得結(jié)果字典或者 None。得到結(jié)果字典后具體怎么處理就看你接下來的發(fā)揮啦。以上,僅供大家參考,期待多交流指正。
來霍格沃茲測試開發(fā)學(xué)社,學(xué)習(xí)更多軟件測試與測試開發(fā)的進階技術(shù),知識點涵蓋web自動化測試 app自動化測試、接口自動化測試、測試框架、性能測試、安全測試、持續(xù)集成/持續(xù)交付/DevOps,測試左移、測試右移、精準(zhǔn)測試、測試平臺開發(fā)、測**理等內(nèi)容,課程技術(shù)涵蓋bash、pytest、junit、selenium、appium、postman、requests、httprunner、jmeter、jenkins、docker、k8s、elk、sonarqube、jacoco、jvm-sandbox等相關(guān)技術(shù),全面提升測試開發(fā)工程師的技術(shù)實力。
獲取更多內(nèi)容:https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=toutiao×tamp=1650790316
拓展知識:
前沿拓展:
c 正則表達式
prce著名開源正則庫源碼C包括phpperlpython等語言都直接或間接使用該庫
pcre *re 指向整庫下載
頭文件詳解要看文檔學(xué)習(xí)調(diào)用和使用該庫
文檔都寫著
另外庫開發(fā)者準(zhǔn)備正則間件嵌入程序使程序能解析正則
專正則初學(xué)者練習(xí)正則而設(shè)置學(xué)習(xí)文檔會少
需要熟練整c庫**作流程和常用原理直接去看源碼
提起正則表達式,可能大家的第一印象是:既強大好用但也晦澀難懂。正則表達式在文本處理中相當(dāng)重要,各大編程語言中均有支持(跟 Linux 三劍客結(jié)合更是神兵利器)。正則表達式是對字符串**作的一種邏輯公式,就是用事先定義好的一些特定字符、及這些特定字符的組合,組成一個“規(guī)則字符串”,這個“規(guī)則字符串”用來表達對字符串的一種過濾邏輯。(來自百度百科)
個人理解如下:某個大佬為了從字符串中匹配或找出符合特定規(guī)律(如手機號、身份證號)的子字符串,先定義了一些通用符號來表示字符串中各個類型的元素(如數(shù)字用 d 表示),再將它們組合起來得到了一個模板(如:dd模板就是指代兩個數(shù)字),拿這個模板去字符串中比對,找出符合該模板的子字符串。
由幾個例子去進一步理解,比如現(xiàn)在有一個字符串為:1.test是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它既可以匹配tester中的test,又可以匹配第二個test。正則表達式中的test就代表test這個單詞本身。
2.btestb是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它只能匹配第二個test。因為b具有特殊意義,指代的是單詞的開頭或結(jié)尾。故tester中的test就不符合該模式。
3.testw*是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它匹配出了tester,也匹配出了第二個test。其中w的意思是匹配字母數(shù)字下劃線,表示的是數(shù)量,指有0個或多個w。所以這個正則表達是的意思就是匹配開頭為test,后續(xù)跟著0個及以上字母數(shù)字下劃線的子字符串
4.testw+是一個正則表達式,它的匹配情況:I am a tester, and My job is to test some software. 它只匹配了tester。因為+與不同,+的意思是1個或多個,所以該正則表達式匹配的是開頭為test,后續(xù)跟著1個及以上字母數(shù)字下劃線的字符串。
通過上述幾個例子,應(yīng)該可以看出正則表達式的工作方式,正則表達式由一般字符和元字符組成,一般字符就是例子中的‘test’,其指代的意思就是字符本身,t匹配的就是字母t;元字符就是例子中有特殊含義的字符,如w, b, *, +等。后續(xù)介紹一些基礎(chǔ)的元字符。元字符有很多,不同元字符有不同的作用,大致可以分為如下幾類。有些元字符專門用來指代字符串中的元素類型,常用的如下:
通過上述表格中的數(shù)據(jù)可以發(fā)現(xiàn),w,d,s都有一個與之相反的元字符(將對應(yīng)字母大寫后就是了)。w匹配所有字母數(shù)字下劃線,那么W就是匹配所有不是字母數(shù)字下劃線的字符。只要記住其中3個,另外3個就很好記了。乍一看這幾個元字符挺簡單的,但是經(jīng)常不用的話保不準(zhǔn)會忘記,此處分享一下我的記憶方法。我把這幾個元字符都當(dāng)作是某一個單詞的縮寫(雖然可能就是某個單詞的縮寫,但是沒有找到準(zhǔn)確的資料去印證):
s是space(空間)的縮寫d是digit(數(shù)字)的縮寫w是word(可以理解成不是傳統(tǒng)意義上的單詞而是代碼中的變量名,變量名可包含的元素就是字母數(shù)字下劃線)的縮寫好了,看到此處你應(yīng)該已經(jīng)熟記了6個元字符了。接下來,n和t平時會經(jīng)常用到,這個肯定比較熟了,最后一個元字符‘.’可以理解它匹配一行中的所有元素,因為遇到換行符后就不再進行匹配了(萬事萬物源于一點)。有些元字符用于表示某種元素的數(shù)量,如d表示一個數(shù)字,當(dāng)你想表示6位數(shù)字怎么辦?當(dāng)然可以dddddd ,但確實太麻煩了,為了簡便就需要一些表示數(shù)量的元字符,上述可以寫成d{6},元字符詳情如下:這幾個元字符還算比較好記。表示0個或多個+表示1個或多個(這個可能會混淆,或許你可以這么記, 表示10=0或多個,+表示1+0=1或多個)?表示0或1個,可以理解成某個人在問你這個類型的元素有還是沒有呀?你回答可能有(1)也可能沒有(0)。剩下的三個只要記住大括號是用來表示數(shù)量,后續(xù)我們還會看到除了{}外,還有[]和()。它們各有各的作用。有些元字符沒有具體的的匹配項,它只是一個抽象的位置概念,它用來表示字符串中的各個位置。一個字符串的位置可以分成:字符串的開頭或結(jié)尾、單詞的開頭或結(jié)尾。如字符串‘I am a tester_.’,I前面是字符串的開頭位置,英文句號后面為字符串的結(jié)尾位置,每一個word(注意此處指的不是傳統(tǒng)意義上的單詞)前后的位置即為單詞的開頭或結(jié)尾,對于‘tester_’來說t前面是單詞開頭,下劃線是單詞結(jié)尾。其中b在前面的例子中有說過,此處可以以這種方式記憶:b是block(塊)的縮寫,即一個單詞是一塊內(nèi)容,b是這一塊的邊界。至于另外兩個元字符,暫時沒找到很好的記憶方法(^一個尖角,小荷才露尖尖角?),但應(yīng)該也不難記。此處有個地方要提及一下,所有表示位置的不會實際占用字符。為了理解可以繼續(xù)看最上面的第二個例子,btestb最終匹配出來了子字符串“test”,而不是“ test ”。大家依據(jù)目前了解的元字符概念,可以思考一下這個正則表達式^d{6,10}$,和d{6,10}的區(qū)別。針對字符串‘12345678‘,第一個和第二個都可以匹配出’12345678‘。但是針對字符串’W12345678‘,只有第二個可以正確匹配出’12345678‘,原因在于第一個正則表達式的意思匹配一個字符串只有6-10個數(shù)字組成,而第二個正則表達式意思是匹配字符串中的6-10個連續(xù)數(shù)字。除了這三個元字符表示位置外,還有零寬斷言、負向零寬斷言也表示位置,后續(xù)會詳細介紹。字符轉(zhuǎn)義的概念大家肯定不陌生,對于, +等有特殊意義的元字符,假如你想匹配5個號應(yīng)該怎么寫,{5}嗎?肯定不是,這樣寫是語法錯誤,應(yīng)該使用將其轉(zhuǎn)義:*{5}。這樣一來*的特殊意義就被給取消了,想要匹配的話,也是一樣,再用一個把特殊意義取消掉就好了。前面列出了部分用于表示意義的元字符,但是可能這幾個元字符覆蓋的都太廣泛了,想要具體的匹配某一類字符。比如就是想匹配abcd這四個字符中的某一個,正則表達式當(dāng)然也是支持的。這時候就需要用到第二種括號,中括號。匹配abcd中的某一個可以寫成[abcd]或者[a-d],意思是匹配一個a-d中的任意字符。相反若匹配非abcd的任意字符,可以寫成[^abcd],意思是匹配一個不是abcd的字符。括號內(nèi)也可以寫入不同類型的元素,如[a-d1-7@],表示的是匹配一個a-d或1-7或@中的任意字符,[^a-d1-7@]則與之相反講完中括號后我們可以看一下小括號(),小括號的意思是分組,即小括號內(nèi)部的所有元字符是一個整體。之前有學(xué)過表示數(shù)量的元字符,但是那個表示的數(shù)量都是針對于一個元字符來說的,比如ab+表示的是匹配一個a后面跟著1個或多個b的子字符串。倘若我們想要匹配的是1個或多個ab(如:abababab),此時分組就派上作用了,可以這么寫:(ab)+。此時ab被綁定為一個整體,后面的數(shù)量元字符對這個整體起作用。元字符中有一個或運算符,它與大多數(shù)編程語言類似都是用 | 來表示。它的作用為:Ab|aB表示的是匹配Ab或者aB。通過這個例子可以很直觀的理解該元字符的作用。當(dāng)然它也經(jīng)常和分組一起使用:(Ab|aB)+c,該正則匹配開始為1-N個Ab或aB之后是c的子字符串,如:AbaBc, AbAbAbaBc。后向引用的使用是依附于分組的,分組的概念之前講過了。第一,我們先看一下正則表達式中組號的分配方式,此時先看一個用到分組的正則表達式:(ab)?(c|C)d。這個正則的意思大家現(xiàn)在肯定都清楚了。這個正則表達式里面用到了兩個分組分別是(ab)和(c|C)。正則內(nèi)部會對所有分組進行組號分配,從左向右,第一個分組(ab)的組號是1,第二個分組(c|C)的組號是2。而組號0代表的是整個正則表達式。嘗試過python正則的此處應(yīng)該有印象,匹配對象的group方法傳參為0或不傳則返回整個正則所匹配的結(jié)果,傳參為1為第一個分組匹配的結(jié)果。了解了組號分配方式后,可以開始解釋后向引用了。后向引用就是將前面某個分組已經(jīng)匹配的數(shù)據(jù)拿過來用,第一個分組匹配的數(shù)據(jù)用1代替,第二個分組匹配的數(shù)據(jù)用2代替,依次類推。似乎不是特別好理解,直接看例子吧,(ab)?(c|C)d2D該正則中2表示的是第二個分組匹配到的數(shù)據(jù),若第二個分組匹配到了c那么2就是c,反之亦然。所以它能匹配到:abcdcD, abCdCD。不能匹配:abcdCD, abCdcD。通過這個例子可以理解它的作用了吧。當(dāng)然分組除了有自己的組號外,還可以給它自定義組名。不同編程語言中的方式不同,Python中自定義組名的格式為:(?Pexp),Name為你自定義的組名,exp代表任意元字符的組合。后面引用的方法為(?P=name)。所以上面例子可以修改成:(ab)?(?Pc|C)d(?P=CWord)D。上一節(jié)簡單的講了一下正則表達式是如何分配組號的,但其實還有幾個需要注意的地方。雖然組號是從左向右進行分配,但是掃描兩遍,第一遍先分配給未命名的分組,第二遍再分配給命名的分組。所以命名后的分組組號會更大使用(?:exp)可以使一個分組不分配組號,如(?:ab)?(c|C)d2D中(ab)就沒有分配到組號,而(c|C)組號為1人性是貪婪的,正則表達式與人一樣也是貪婪的。一個正則表達式會盡量多的去匹配字符串,如:ab.+c去匹配’abccccc’是會將該字符串全部匹配出來。但有時候我們只想要其匹配’abcc’,此時怎么辦呢?需要給正則表達式中表示數(shù)量的元字符加一個?變成ab.+?c。此時該正則表達式就變懶了,不會再去匹配那么多,匹配到‘a(chǎn)bcc’就完事了。這兩個個概念有些不太好理解。正如前面所說這兩個也是表示位置的元字符。從字面意思上理解,零寬代表其沒有寬度,即如之前介紹表示位置的元字符中提到的一樣,不會實際占用字符。斷言是什么?是assert,是用來判斷條件是True還是False。理解完這兩個詞語的意思后,零寬斷言的概念應(yīng)該也就能理解了。那么負向無非就是它的反義詞。上面的表格主要看第一列它是什么格式就好,反正后面的名稱和說明也很難看懂。接下來我來用自己的理解通俗的解釋一下這些概念。第一字符串中可以有四種方式確認(rèn)某個子字符串的位置,如字符串‘BACAB’中有兩個A,A前面是B、A前面不是B、A后面是C、A后面不是C。上述四種條件都能夠匹配出唯一一個子字符串A。這個例子大概理解的話就可以往后看了。(?=exp)中exp指代的是任意元字符的組合,結(jié)合具體的例子來理解該元字符的用法,一個正則表達式為A(?=C),它代表的情況就是A后面是C的情況。所以匹配出了第一個A,由于該元字符是零寬所以它只能匹配出A而不是AC。(?<=exp)與上面用法相反,一個正則表達式為(?<=B)A,它代表的情況就是A前面是B的情況。所以匹配出了第一個A。如果改成(?<=C)A,則能匹配出第二個A。(?!exp)的例子為:A(?!C),它代表的情況為A后面不是C,所以匹配出第二個A。(?<!exp)的例子為:(?<!B)A,它代表的情況為A前面不是B,所以匹配出第二個A。通過上面四個例子的介紹,應(yīng)該對于這兩個概念、四個元字符有了了解。理解是重點,記下來也是重點。本人是這樣記下來的,四個元字符的基本格式都是(?),只不過問號后面的不一樣。分下面兩種情況:XXX前/后是XXX的話就寫一個=,XXX前/后不是XXX的話就寫一個!。這個和日常用的=和!=差不多。如果表示的意思是前的話,這個元字符就需要出現(xiàn)在前面且要加一個類似于向前指的箭頭<。如果表示的意思是后的話,就什么都不需要加。通過上面兩個情況的歸納,是不是這四個元字符就都記下來了?到目前為止,正則表達式的基本內(nèi)容都介紹完了。但是文中用的例子都比較簡單,只能幫助你理解概念。如果感興趣或者工作中能用到的話,還需要后續(xù)勤加練習(xí)。你以為文章到小編綜合來說就結(jié)束了?So naive,我再來列舉一個測試日常工作中的案例,將理論應(yīng)用到實踐(編程語言選擇 Python,因為我目前只會這個)。設(shè)想這么一個場景,在測試過程中需要獲取某個時間段內(nèi)某個程序的運行情況,從而分析出該程序的穩(wěn)定性或使用頻率等指標(biāo),該程序的日志記錄完備,日志格式固定且已知。這時候最佳的辦法就是從該程序日志中進行相關(guān)信息的獲取。假如該日志內(nèi)容格式大概如下(注:該日志樣例不是實際項目中的日志文件,為個人舉例):從這個日志中可以看到訪問成功的IP及其認(rèn)證賬號、訪問失敗的IP、程序的錯誤信息。那么我們怎么把這些數(shù)據(jù)給抓取出來呢?抓取的方法肯定有很多,如果此時你第一時間想到了正則表達式,那么恭喜你,通過閱讀前面的文章,正則已經(jīng)在你心中留下了痕跡,或者它本來就留有痕跡。我們先來分析一下第一條日志,其余的與此類似,有用的信息可以分成如下幾個片段:時間字符串:2020-02-17 11:04:34日志級別:INFOIP:182.168.3.111認(rèn)證郵箱:110232123@qq.com狀態(tài)碼:1客戶端獲取到的數(shù)據(jù)大?。?2931KB上面幾個片段對應(yīng)的正則為:時間字符串:d{4}-d{2}-d{2}s*d{2}:d{2}:d{2}日志級別:[INFO]IP:(d{1,3}.){3}d{1,3}認(rèn)證郵箱:w+@w+.w+狀態(tài)碼:d+客戶端獲取到的數(shù)據(jù)大小:d+KB上述中某幾個正則其實并不嚴(yán)謹(jǐn),比如IP對應(yīng)的正則還可以匹配出999.999.999.999。嚴(yán)謹(jǐn)?shù)恼齽t表達式是((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)。由于該正則太長,加之此處重點在于如何應(yīng)用,故暫用其寬松版的正則表達式。知道了各個字段的正則后,我們可以將它們各自寫成一個分組,分組之間填充上其余元字符,把匹配整行日志的正則表達式寫出來,如下:現(xiàn)在我們通過這個正則表達式可以抓取出日志文件中這種格式的日志字符串,再根據(jù)組號就可以拿出來對應(yīng)的數(shù)據(jù)了。不過根據(jù)組號取數(shù)據(jù)可能會有些含糊不清,或許我們可以給每個分組進行命名(使用python支持的方式),形成如下正則表達式:好了現(xiàn)在我們可以很清楚的看到,表示時間的分組命名為Time,依次類推。接下來,我們可以使用上述正則表達式去抓取一行日志,再通過分組的名稱拿到對于的字符串?dāng)?shù)據(jù)了。具體的代碼可以參考下面的樣例:代碼中實現(xiàn)了一個函數(shù)reg_deal,后面代碼都是對于這個函數(shù)的實際應(yīng)用,該函數(shù)入?yún)椋赫齽t表達式組成的列表、待匹配的字符串、特殊函數(shù)組成的字典。其先循環(huán)將字符串與列表中各個正則表達式進行匹配,匹配成功后得到一個匹配對象,調(diào)用該匹配對象的groupdict函數(shù)可以返回一個結(jié)果字典,該結(jié)果字典的鍵為分組的名稱,值為分組匹配到的值。針對這一結(jié)果字典再進行一步特殊函數(shù)處理,如上述中的status字段日志中是碼值,但輸出結(jié)果需要是具體的漢字。故對其進行了一步碼值轉(zhuǎn)換**作,對與數(shù)據(jù)大小將KB轉(zhuǎn)化成了MB。若使用該函數(shù),需自己將正則表達式寫出來并對正則表達式中的分組進行命名,若有些分組數(shù)據(jù)需要特殊處理,則維護一個特殊函數(shù)字典,鍵為分組名,值為函數(shù)(匿名函數(shù)或者是函數(shù)名稱)。將參數(shù)傳入后即可獲得結(jié)果字典或者 None。得到結(jié)果字典后具體怎么處理就看你接下來的發(fā)揮啦。以上,僅供大家參考,期待多交流指正。
來霍格沃茲測試開發(fā)學(xué)社,學(xué)習(xí)更多軟件測試與測試開發(fā)的進階技術(shù),知識點涵蓋web自動化測試 app自動化測試、接口自動化測試、測試框架、性能測試、安全測試、持續(xù)集成/持續(xù)交付/DevOps,測試左移、測試右移、精準(zhǔn)測試、測試平臺開發(fā)、測**理等內(nèi)容,課程技術(shù)涵蓋bash、pytest、junit、selenium、appium、postman、requests、httprunner、jmeter、jenkins、docker、k8s、elk、sonarqube、jacoco、jvm-sandbox等相關(guān)技術(shù),全面提升測試開發(fā)工程師的技術(shù)實力。
獲取更多內(nèi)容:https://qrcode.ceba.ceshiren.com/link?name=article&project_id=qrcode&from=toutiao×tamp=1650790316
拓展知識:
原創(chuàng)文章,作者:九賢生活小編,如若轉(zhuǎn)載,請注明出處:http://xiesong.cn/42411.html