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