Perl+正則表達式講解_第1頁
Perl+正則表達式講解_第2頁
Perl+正則表達式講解_第3頁
Perl+正則表達式講解_第4頁
Perl+正則表達式講解_第5頁
已閱讀5頁,還剩23頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、目錄:Perl正則表達式講解摘自Perl編程詳解931原則1正則表達式有三種形式:匹配、替換和轉(zhuǎn)換。在表9-1中列有三種正則表達式運算符。表正酬表達弍運31符八運算符m/M*接下來對每一個表達式給出詳盡解釋。匹配:m/regexp/這種形式表明在/內(nèi)部的則表達將用于匹配=或!左邊的標量。為了語法上的簡化用/regexp/,略去m。替換:s/regexp/substituteText/這種形式表明則表達式regexp將被文本substituteText替換,為了語法的簡化用/regexp/substituteText略去s。轉(zhuǎn)換:tr/charClass/substituteClass/這種形式

2、包含一系列的字符一/charClass一同時把它們替換為substituteClass。注意轉(zhuǎn)換tr并不真是一個則表達式,但是對于用正則表達式難于處理的數(shù)據(jù)常使用它來進行操縱。因此,tr/0-9/9876543210.組成1223456789,987654321等字符串。通過使用=(用英語講:does,與“進行匹配”同)和?。ㄓ⒄Z:doesnt,與“不匹配”同)把這些表達式捆綁到標量上。作為這種類型的例子,下面我們給出六個示例正則表達式及相應(yīng)的定義:$scalarName=s/a/b;#substitutethecharacteraforb,andreturntrueifthiscanhapp

3、ern$scalarName=m/a;#doesthescalar$scalarNamehaveanainit?$scalarName=tr/A-Z/a-z/;#translateallcapitalletterwithlowercaseones,andrentutrunretureifthishappens$scalarName!s/a/b/;#substitutethecharacteraforb,andreturnfalseifthisindeedhappens.$scalarName!m/a/;#doesthescalar$scalarNamematchthecharactera?Re

4、turnfalseifitdoes.$scalarName!tr/0-9/a-j/;#translatethedigitsforthelettersathruj,andreturnfalseifthishappens.如果我們輸入像hornedtoad=m/toad/這樣的代碼,則出現(xiàn)圖9-1所示情況:另外,如果讀者正在對特定變量$_進行匹配(讀者可能在while循環(huán),map或grep中使用),則可以不用!和=。因而,以下所有代碼都會合法:myelemente=(al,a2,a3,a4,a5);foreach(elements)s/a/b/;程序使elements等于b1,b2b3,b4,b5

5、。另外:while($FD)printif(m/ERBOR/);打印所有包含error字符串的行:if(grep(/pattern/,lines)print“thevariablelineshaspatterninit!n”;打印所有包含模式pattern內(nèi)容的行,這直接引入下一原則。932原則2正則表達式僅在標量上匹配。注意這里標量的重要性,如果讀者試一試如下代碼:arrayName=(variablel,variable2);arrayName=m/variable/;#looksforvariableinthearray?No!usegrepinstead那么arrayName匹配不成功

6、!arrayName被Perl解釋為2,于是這意味著讀者在輸入:2=m/variable/;至少講這不能給出預(yù)想的結(jié)果。如果讀者想這樣做,輸人為:grep(m/variable/,arrayName);該函數(shù)通過arrayName中的每一個元素進行循環(huán),返回(在標量環(huán)境中)匹配的次數(shù),同時在數(shù)組環(huán)境中返回匹配元素的實際列表。933原則3對于給定的模式串,正則表達式只匹配最早出現(xiàn)的匹配項。匹配時缺省一次只匹配或替換一次。這個原則使用稱為“回溯”的過程指出如何匹配一個給定的字符串;如果發(fā)現(xiàn)了一個局部匹配進而找到使該匹配無效的東西,正則表達式在字符串中“回溯”最小的可能數(shù)量,這個數(shù)量的字符要保證不丟

7、失任何匹配。對于理解正則表達式正在做什么,這個原則是最有幫助的一個,同時不需要與Perl一樣的形式來理解它正在做什么。假定有如下模式:Sillypeopledosillythingsifinsillymoods同時想匹配如下模式:sillymoods那么正則表達式引擎匹配silly,接著遇到people的P,至此,正則表達式引擎知道第一個silly不匹配,于是正則表達式引擎移到P且繼續(xù)尋求匹配。它接著遇到第二個silly,于是來匹配moods。然而得到的是字母t(在thing中),于是移到things中的t處,繼續(xù)進行匹配。當(dāng)引擎遇到第三個silly并且盡力匹配moods時,匹配成功,匹配最后

8、完成。所發(fā)生的情況如圖9-2所示。當(dāng)我們遇到通配符時回溯將變得更加重要。如果在同一正則表達式中有幾個通配符,且所有的通配符交織在一起,那么這里就有病態(tài)情形出現(xiàn),在這種情形下,回溯變得非常昂貴??慈缦卤磉_式:$line=m/expression.*matching.*could.*be.*very.*expensive.*/.*代表一個通配符,它意味著“匹配任意字符(換行符除外)零次或多次”。這個過程有可能花很長時間;如果在未匹配過的字符串末尾有可能匹配,那么引擎將發(fā)狂地回溯。為得到這方面的更多信息,請留意關(guān)于通配符方面的原則。如果讀者發(fā)現(xiàn)類似于上面的情形,那么通配符需將正則表達式分解成小功部分

9、。換句話講,簡化自己的正則表達式。Sscalar=sillypeopledosillyrhtngsifinsillymoods;$冷亡曲ar匸m/sdlyeakJE;parualmatchsillypeopledosillythingsifinsiHjmoodsMjfynoods、杠lymoodsmismatchpatternslidesupPbckirck5(obeginninghsoshcanmatchagitnsillypeopledosillyUiingsifinsiNymoodspatTcmslidesu仙backcnckstobeginnwg,so號*cnnmictiagainsi

10、llypeopledosiHythingsifinsillymoodssillymoodsputemmatchesfuiJy9.3.4原則4正則表達式能夠處理雙引號字符串所能處理的任意和全部的字符。在s/運算符(s/*/),或者m/運算符m/*/的第一個分隔區(qū),位于其中的條目確實能像雙引號字符串一樣對待(帶有一些額外的附加功能,名義上的特殊正則表達式字符!后面描述)。讀者可用他們進行內(nèi)插:$variable=TEST;$a=m/$variableaha/;和:$a=$variableaha;二者都指向同一字符串:前者在$a中匹配字符串TESTaha.后者把$a設(shè)置為字符串TESTaha。因為正

11、則表達式處理雙引號字符串能處理的每個字符,所以可以執(zhí)行下列操作:$expression=hello;arrayName=(elem1,elem2);$variable=m/$expression/;#thisequalsm/hello/;在這里,我們簡單地把$expression擴展為hello而得到m/hello/。這個技巧也可用于數(shù)組:$variable=m/arrayName/;#thisequalsm/elem1elem2/;在這里,表達式等價于m/elemlelem2/如果特殊變量$被設(shè)置為|.則表達式將等價于m/elem|elem2/,正如我們看到的,它匹配字符串的elem或者el

12、em2。這種方法也可應(yīng)用于特殊字符:$variable=m/x0l27/;#matchbinarycharacterx0l,and#octalcharacter27.$variable=s/ttt/;#substitutethreetabsforthreespaces.實際上,這里所討論的除極少數(shù)例外以外,Perl處理在m/中的過程的確像處理在雙引號中的一樣。但是有例外:有某些對正則表達式引擎有明確意義的字符。那么,如果想匹配類似于正斜杠(/)或者園括引()這樣的字符會發(fā)生什么呢?這些字符對正則表達式引取有特殊意義:因而不能使用如下語句:$variable=m/usr/local/bin/;#

13、matches/usr/local/bin?NO!SYNTAXERROR因為Perl將把/解釋為正則表達式的結(jié)束標記。這里有三種方法去匹配類似于上述特殊字符的方法。第一種方法是利用反料杠來“轉(zhuǎn)義”想匹配的任意特殊字符一包括反斜杠。因而剛才給出的例子可變?yōu)椋?path=m/usr/local/bin/;該程序盡力匹配$path中的/usr/local/bin。第二種方法是使用一個不同的正則表達式字符。如果有許多字符要匹配,那么使用反斜杠則會變得很難看(路徑字符尤其不好)。幸運的是,Perl以一種合成形式來確決這個問題。因為在當(dāng)讀者輸入m/或s/時需要給每個/加反斜杠,所以正則表達式允許讀者將正則

14、表達式的定界符(/)改為自己喜歡的任意字符。例如,我們可以使用雙引號()來避免大量的反斜杠:$variable=m/usr/local/bin;#Notethequotationmarks.$variable=mhelp;#Ifyouaregoingtomatchquotation#marks,youneedtobackslashthemhere.(asper)$variable=S$variable$variable;#worksins/too.出于好的初衷,我們在本書的前幾章使用了這一約定。如果使用作為讀者的正則表達式字符,那么在用起來時它充當(dāng)了好的記憶法,記住在這里所處理的實際上是字符串

15、的變相反插入;否則,引號就遠不如斜杠常用。Perl允許使用()來書寫正則表達式:$variable=mthisworkswellwithvioremacsbecausetheparensbounce;$variable=m(thisalsoworkswell);$variable=s(substitutepattern)forthispatternsg;這一原則對我們處理多行正則表達式非常方便。因為在這里可以不用圓括號,所以讀者可以開始把表達式作為“微型函數(shù)”對待(如果讀者有像emacs或vi這樣的合理的智能編輯器),換句話講,讀者可在表達式的開始和結(jié)尾部分之間往返。第三種方法是利用函數(shù)quo

16、temeta()來自動地加反斜杠。如果輸入如下代碼:$variable=m$scalar;則$scalar將為被插且被轉(zhuǎn)變?yōu)闃肆康闹怠_@里有一個警告:任何一個特殊字符都將被正則表達式引擎影響,并且可能引起語法錯誤。因此,如果標量為:$scalar=(;那么輸入如下代碼:$variabie=m$scalar;就等價于是說:$variable=m(,而這是一個運行時語法錯誤。如果表達式為如下形式:$scalar=quotemeta();則表達式會$scalar變?yōu)?,且把$scalar替換為:$variable=m(;這樣才可以匹配到讀者愿意匹配的字符串(。935原則5正則表達式在求值的過程中產(chǎn)生

17、兩種情況:結(jié)果狀態(tài)和反向引用。每次對正則表達式求值時會得到:指示正則表達式匹配字符串的次數(shù)(結(jié)果狀態(tài))。如果希望保存部分匹配,則有系列稱為反向引用的變量。接下來讓我們依次學(xué)習(xí)他們:1結(jié)果狀態(tài)結(jié)果狀態(tài)表示正則表達式匹配字符的次數(shù)。得到結(jié)果狀念的方法是在標量環(huán)境下求正則表達式的值。以下所有例子使用了這結(jié)果變量。$pattern=simplealwayssimple;$result=($pattern=msimple);這里,result為1,因為模式simple位于simplealwayssimPle中。同樣的,給定simplealwayssimple:$result=($pattern=mcom

18、plex);將使result為空,因為complex不是simplealwayssimple的子字符串,接著:$result=($pattern=ssimplecomplex);使result為1,因為把simple替換為complex成功了。更進一步:$pattern=simplesimple;$result=($pattern=ssimplecomplexg);情況變得更復(fù)雜。在這里,$result為2,因為在simplealwayssimple中simple出現(xiàn)兩次,同時正則表達式的g修飾符被使用,這意味著“匹配盡可能多的次數(shù)”。(要更詳細材料參看本章后面的修飾符)。同樣地:$patte

19、rn=simplestill;if($pattern=msimple)printMATCHED!n;在f子句中使用$pattern=msimple而該子句基本上告訴Perl,如果模式$pattern包含有子串simple則打印Matched!。2反向引用反向引用有點復(fù)雜。假定想保存一些匹配供后用,那么為達到該目的,Perl有一個運算符(圓括號(),該運算符可用于包圍讀者希望匹配的一系列給定的字符。在正則表達式中用圓括號括住某模式就是告訴解釋器“嗨,我希望保存那個數(shù)據(jù)。”Perl解釋器再應(yīng)請求,且將查找到的匹配保存在一系列特珠的變量中($1,$2,$3$65536),這些變量可用來查詢第一個、第

20、二個、第三個等等圓括號匹配,這些變量于是可以通過查看相應(yīng)的變量或在數(shù)組環(huán)境下對正則表達式進行求值而且進行訪問。例如:$text=thismatchesTHISnotTHAT;$text=m(TH.);print$1n;在這里,字柳HIS被打印出來Perl已經(jīng)將它們保存在$1中,以后再打印$1。然而,該例子揭示了更多內(nèi)容,例如:通配符(字符點()匹配任意字符)。如果THIS不在字符串中,模式(TH.)將欣然匹配THAT。正則表達式匹配一行上出現(xiàn)的第一處模式。THIS因為首先出現(xiàn),所以被匹配。同時,按缺省regexp行為,THIS將總是被匹配的第一個字符串。(可以用修飾符改變?nèi)笔≈?,詳細情況稍后介

21、紹)。圖9-3表示了這一匹配過程如何進行。在圖9-3中每個圓括號與自已的數(shù)字變量一道運行。:Stext=maiches,TH3S,and,THAT;jStext亠mTTHJWTH.);prinlSI;$tX!=,1thi5ffiMchesfTHl?$FidItHATJ1;雷曲”噸里頁兩3;AuiviuSl!S1?:THIS*)($2=THATrDiscardthestringand這里有更多的例子:rioparnixwws)$text=Thisisanexampleofbackreferences;($example,$backreferences)=($text=m(example).*(b

22、ackreferences);這里又用了通配符來分開兩個文本字符串exampl奮和和$backrferences。這些字符串存放在$1和$2中,且隨后立即賦給$example和$backrefercences。該程在圖9一4中說明。(text=Thisisanexampleofdotsofbackreferences*;(Se;tainplG$fHlE!Sbackrefereoces)=($textirrOxampgHFXbacEftreiicesF);$Uxt竽Thisisan&l玨flots(iexainpie;疋farference;-(Sexample,Sfiller,$back

23、refmnce$)=(ewinplc1,1oflotsofbackreferences);Sexample二Texampkfiner=PflotsoCIBAcldcteiences=陸kj幀Rtces芍s-1是空的。這里有更好的同樣然而應(yīng)注意的是當(dāng)文本字符串匹配時,給$example和$bacbreference賦值的過程才發(fā)生。當(dāng)文本字符串不匹配時,$example的例子,該例子包含在if語句中,在匹配if($text=m(example).*(back)print$1;#printsexample-sincethefirstparensmatchthetextexample.print$2

24、;#printsback-sincethesecondparensmatchthetextback這樣,如果正則表達式根本不匹配將發(fā)生什么?如果使用下面的模式:$text=Thisisanexampleofbackreferences;$text=s(examplar).*(back)doesntwork;print$1;$1因則表達式匹配不成功而不能被賦值。更重要地,Perl不會告訴讀者它沒有給$1賦任何值。最后一例展示了關(guān)于正則表達式的兩點重耍內(nèi)容:則表達式是“要么全部要么什么也沒有”的處理,只因為back字符串在模式內(nèi)才能匹配,所以:Thisisanexampleofbackrefere

25、nces并不意味著整個表達式達到匹配。因為exemplar不在字符串中,因而替換失敗。如果正則表達式失敗,反向引用不能得到賦值。因此,不能肯定將打印出什么內(nèi)容。$a=bedbugsbite;$a=m(bedbug);3$b=thisisnasty;$b=m(nasti);67print$1;當(dāng)跟蹤邏輯問題時,這就是讓人吃驚的原因;且經(jīng)常是Perlgotcha$1只是一個則變量,并且(與Perl語法相反)如果則表達式失敗則反向引用不被設(shè)置為“空白”。有人認為這是一個缺陷,然而另有人認為這是一個特色。不過,當(dāng)分析下面的代碼時第二點變得非常明顯。sets$1tobebedbug.doesNOTset

26、$1(nastiisnotinthisisnasty).BUT$1isstillsettobedbug!printsbedbug.在這種情況下,$1為字符串bedbug,因為第5行的匹配失?。∪绻M玫絥asti,好吧,那是自己的問題。這種Perl化的行為可能讓人不知所措。考慮的是自己要當(dāng)心。3使用反向引用的一般構(gòu)造法如果想避免這種很平常的缺陷(讀者想得到一個匹配,但是沒有得到并且用前面的匹配為替代而結(jié)束),在把反向引用賦給變量時只要應(yīng)用下列三個構(gòu)造法之一:短路方法。核查匹配,如果匹配發(fā)生,此時且只有此時用&進行賦值,例如:($scalarName=m(nasti)$matched=$1;i

27、f子句。將匹配放于if子句中,如果if子句為真,此時且只有此時才為模式賦值。if($scalarName=m(nasti)$matched=$1;elseprint$scalarNamedidntmatch;直接賦值。因為可以直接把正則表達式賦給一個數(shù)值,所以可始終利用這一點。($match1,$match2)=($scalarName=m(regexp1).*(regexp2);讀者的所有模式的匹配代碼看起來應(yīng)該與前述三個例子中的一個相似。缺少這些形式,那么就是在沒有安全保證的條件下進行編碼。如果讀者從不想有這種類型的錯誤的話,那么這些形式將節(jié)省讀者的大量時間。4在正則表達式中使用反向引用當(dāng)

28、希望使用s運算符或者用m運算符對一些復(fù)雜模式進行匹配很困難時,Perl提供了讀者應(yīng)意識到的有用功能。這個功能就是反向引用可以用于正則表達式自身。換句話說,如果用圓括號括住一組字符,那么就可以在正則表達式結(jié)束之前使用反向引用。如果想在s的第二部分(帶下劃線)中使用反向引用,那么要使用語法$1,$2等。如果想在m或者s的第一部分(帶下劃線)使用反向引用,那么使用語法12等。下面是一些例子:$string=farout;$string=s(far)(out)$2$1;#Thismakesstringoutfar.我們在該例中只是將單詞farout轉(zhuǎn)換為outfar。$string=sampleexa

29、mples;if($string=m(amp.)ex1)printMATCHES!n;這個例子有點復(fù)雜。第一個模式(amp.)匹配字符串a(chǎn)mple。這意味轉(zhuǎn)整個模式成為字符串a(chǎn)mpleexample,其中帶下劃線的文本對應(yīng)于1。因此,模式匹配的是sampleexamples。下面是同樣風(fēng)格更復(fù)雜的例子;$string=bballball;$string=s(b)1(a.)12$1$2;讓我們詳細地看看這個例子。該例完成匹配,但是原因不是太明顯。對這個字符串的匹配有五個步驟:在圓括號中的第一個b匹配字符串的開頭,接著將其存放在1和$1中。1于是匹配字符串中的第二個b,因為與b相等,而第二個字符碰

30、巧是b。(a.)匹配字符串a(chǎn)ll且被存在2和$2中。1匹配下一個b。因為2等于all所以匹配下一個且是最后三個字符(all)。將他們放到一起就得到則表達式匹配bballball,或者說是整個字符串。既然$1等于b,$2等于all,則整個表達式:$string=bballball;$string=s(b)1(a.)12$1$2;(在這個例子中)轉(zhuǎn)換為如下代碼:$string=s(b)b(all)ballball;或者用行話講,用bballball替換ball。正則表達式看起來很像圖9-5所示。SstringSstring=s7b)U(a.)l2$l$2;(b)l(a)U2bballballbba

31、Uball.bbaUballSsbjng二y*尿1(孔.應(yīng)淫1$2“;JGyring十論他顧麗而(孑斤(09-5正則表達式例子s中有一些復(fù)雜的反向引用。如果理解了最后一個例子。那么讀者在理解Perl的正則表達式如何工作方面遠遠走在了前面。反向引用可能而且確實會變得更糟。5嵌套反向引用嵌套反向引用對于復(fù)雜的難以用單一順序(一個字符串跟在另一個字符串后面)進行匹配的字符串作用明顯。例如下面的表達式:m(aaa)*);使用*來匹配多次出現(xiàn)的aaa:即匹配,aaa,aaaaaa,aaaaaaaaa。換句話說,Perl匹配一行中有多個3a的模式。但是這個模式不會匹配aa。假定想匹配如下的字符串:$str

32、ing=softlyslowlysurelysubtly;那么使用嵌套園括號后下面的正則表達式會匹配:$string=m(s.lys*)*);#notenestedparens.在該例中,最外層的圓括號捕獲全部字符串:softlyslowlysurelysubtly。最內(nèi)層的圓括號捕獲字符串的組合,這種組合是以s開頭,以ly結(jié)尾且ly后跟空格形成的。因此,正則表達式先捕獲surely,其拋開,然后捕獲slowly,其拋開,然后捕獲surely,最后捕獲subtly。這里有一個問題,反向引用按什么順序出現(xiàn)?讀者可能在這個問題上很容易迷惑。是外層圓括號先出現(xiàn)呢,還是內(nèi)層的內(nèi)括圓號先出現(xiàn)?最簡單的解

33、決辦法是記住以下三條原則:在表達式中,一個反向引用越在前,它對應(yīng)的反向引用編號就越小。例如:$var=m(a)(b);該例中,反向引用(a)變?yōu)?1,(b)變成了$2。一個反向引用如果它包含范圍越廣,則它的反向引用編號就越小。例如:$var=m(c(a(b)*)*);該例中,包含全部內(nèi)容(m(c(a(b)*)*)的反向引用成為$1。有a嵌套在里面的表達式m(c(a(b)*)*)成為$2。在(m(c(a(b)*)*)中帶有b的嵌套表達式成為$3。在兩個規(guī)則沖突的情況下,規(guī)則1優(yōu)先。在語句$var=m(a)(b(c)中,(a)成為$1,b(c)成為$2,(c)成為$3。因而,在這個例子中,(s.l

34、ys*)*成為$1,(s.lys*)*成為$2。注意這里有另一個問題。讓我們一起返回到剛開始的復(fù)雜的正則表達式:$string=softlyslowlysurelysubtly$string=m(s.lys*)*);#notenestedparens.這里(s.lys*)*匹配什么呢?它匹配多個字符串;首先是softly,接著是slowly,再接著是surely,最后是subtly。既然(s.lys*)*匹配多個字符串,那么Perl會拋棄掉第一個匹配而使$2成為subtly。即便有這些規(guī)則,嵌套圓括號仍然可能引起混亂。要做的最好事情就是實踐。再一次用這些邏輯的不同組合去實現(xiàn)正則表達式,然后把它

35、們交給Perl解釋器。這樣做可讓讀者明白反向引用是以什么次序被Perl解釋器進行解釋的。936原則6正則表達式的能力的核心在于通配符和多重匹配運算符。通配符運算符允許匹配字符串中的多個字符。如果正在處理二進制數(shù)據(jù),那么通配符就匹配一系列字符。多重匹配運算符可匹配零個、一個或多個字符。就講解Perl的基礎(chǔ)而言,到目前為止我們所使用的例子都是帶啟發(fā)性的,但功能并不是很強大。實際上,瀆者可能會用C子程序去完成它們中的任意個。Perl正則表達式集合的強大功能來自于其匹配文本的多模式能力,(即:通過前面提到的邏輯“速記法”來描述許多不向的數(shù)據(jù)模式)。Perl正好可提供最好的速記法。1通配符通配符代表字符

36、類。他沒有如下字符串,但不知道他們是否大寫:KumquatKristinaKentuckyKeyKeeping這種情況下,如下的Perl表達式會匹配每個單詞的第一個字符:Kk這是字符類的一個例子。Perl中的所有通配符可以用括號并把想匹配的字符類放在括號中最后加上結(jié)尾括號這種方法表示。前面的通配符告訴正則表達式引擎好,我正在這里查找K或者R。如果發(fā)現(xiàn)兩者之一那么就匹配它”。下面是另一些使用通配符的例于:$scalarName=thishasadigit(1)init;$scalarName=m0-9;#Thismatchesanycharacterbetween0and9,thatismatc

37、hesanydigit.$scalarName=thishasacapitalletter(A)init;$scalarName=mA-Z;#Thismatchesanycapitalletter(A-Z).$scalarName=thisdoesnotmatch,sincetheletterafterthestringANisanA$scalarName=manA;前兩個例子相當(dāng)直觀,0-9匹配thishasadigit(l)init中的數(shù)字1。AZ匹配thishasacapitalletter(A)init中的大寫字符A。最后一例稍有點技巧,因為在這個模式中有一個an,所以可能被匹配的字符

38、唯有最后的四個字符,即anA。然而,通過詢問模式anA我們已經(jīng)明確地告訴正則表達式去匹配a,接著是n,空格,最后一個為非A的字符。因而,該例中沒有完成匹配。如果給定模式為matchanAnotane那么匹配就會完成,因為第一an被跳過后,第二個正好匹配!就像如下例子:$scalarName=Thishasatab()oranewlineinitsoitmatches;$scalarName=mtn#Matcheseitherataboranewline.#matchessincethetabispresent.這個例子說明了用匹配和通配符可以做的一些有趣的事情。首先,讀者已經(jīng)在字符串插入的相同

39、字符也可以在正則表達式和用括號表示的字符類中(tn)插入。其中t匹配制表符,n匹配換行符。其次如果讀者在里的開頭部分放置一個,則通配符會匹配非字符組中的字符。同樣地,如果在中放置-,則通配符匹配給定的范圍(在這個例子中是所有的數(shù)字0-9。所有的大寫字母(A-Z)。這些運算符還可被合并,從而得到相當(dāng)特別的通配符:$a=ma-fh-z;#matchesanylowercaesletter*except*g.$a=m0-9a-zA-Z;#matchesanynonwordcharacter.(i.e.,NOTacharacterin0-9,a-zorA-Z)$a=m0-9A-Za-z;#amista

40、ke,Doesnotequaltheabove.Insteadmatches0-9,$a=mtn;#matchesaspacecharacter:tab,newlineorblank).需許意的重要地方是第三個例子,在o9AZaz中的插入記號是一個字面上的插入記號,而不是代表否定,原因是它在字符類的中間出現(xiàn)。因此,如果讀者想得到一個否定的字符類。那么就總是要把插入記號放在開頭。也不要忘記用。如果讀者忘記了,那么得到的將是一個字面上的文本字符串,而不是一個字符類。(1)公用通配符碰巧某些通配符是公用的;當(dāng)讀者每次想匹配一個數(shù)字時,可能不愿意每次都必須要輸入類似于0-9這樣的代碼。對于那些情況,P

41、erl有幾個方便的快捷通配符,使用它們后可使編程工作容易。下面是這些邊配符以及它們代表的含義和它們對應(yīng)的字符組合:d匹配數(shù)字(字符組合0-9)。D匹配非數(shù)(字符組合0-9)。.w匹配單詞字符(字符組合a-zA-Z0-9_)(這里下劃線算作一個單詞字符)。.W匹配非單詞字符(字符組合a-zA-Z0-9_)。.s匹配空格字符(字符組合tn)(制表符、換行符、空格)。.S匹配非空格字符(字符組合tn)。.-匹配任意字符(在某些情況下)換行符除外(字符組合飛n)、當(dāng)輸入m(.*)S時匹配任意字符。參見本章后面的修飾符。$-盡管它實際上并不是一個通配符(它不匹配任何具體字符)但它是廣泛使用的特殊字符;如

42、果將其放在正則表達式的尾部則它匹配“行尾”。零寬度斷言。-盡管實際上不是一個通配符,但如果它位于正則表達式的開頭則它是匹配“行首”的特殊字符。零寬度斷言。.b,B-與$和相同;不匹配字符,但匹配單詞邊界(b)或匹配無單周邊(B)。零寬度斷言。我們從表中注意到的第一點是“點”通配符(.)。它常與多重匹配運算符一道用于在條目間充當(dāng)填充者。請看以下匹配:$a=NOWisthetimeforallgoodmentocometotheaidoftheirparty;$a=m(Now).*(party);#matches,since.matchesanycharacterexceptnewlineand*

43、meansmatchzeroormorecharacters.*捕獲位于Now和party中間的所有字符,匹配是成功的。(在這種環(huán)境下的“所有”意味著“零或者更多,盡可能多”。這就是所謂的貪夢(greediness);在我們后面談到多重匹配運算時再談它。)下面是通配符的一些其他例子。注意我們在=的左邊使用了單引用字符串(這是一個測試表達式的簡單方法):11956.23=m(d+).(d+);#$1=1956,$2=232333e+12=m(D+)#$1=e+3$hash($value)7=m$(w+)$(w+);#$1=hash,$2=value4$hash($value)7=m$(w+)(w

44、)*(w+)(w*);#$1=$,$2=hash,#$3=$,$4=value5VARIABLE=VALUE=m(w+)(s*)=(s*)(w+);#$1=VARIABLE,#$2=,#$3=,$4=VALUE6catchascatchcan=m(.*)can$;#$1=catchascatch7canascatchcatch=mcan(.*)$#$1=ascatchcatch8word_with_underlinesword2=mb(w+)b;#$1=word_with_underlines每個例子中,我們使用了一個不同的通配符,在該程序中,用*表示在“一行中匹配零個或者多個通配符”。用+表

45、示“在一行中匹配一個或者多個通配符”。這些例子中有些本身就是有用的:例5展示了使用s*來加強表達式對付散亂空格的方法;例8示例了匹配一個單詞的一般化方法;例4示范了使用關(guān)鍵字匹配哈希結(jié)構(gòu)的一般化方法。我們在下面講述侖們。然而,特殊地.例1不是匹配Perl數(shù)字的通用方法。但是如果給出Perl支持的所有格式,那么這會是一個十分困難的問題。我們將在后面把它作為一個問題考慮。在該表中還有一個地方需要注意:一些適配符被標記為“零寬度斷言”(2)零寬度斷言和正寬度斷言在表9-2中的字符就是讀者可能稱作的正寬度斷言表9-2正聲明D非數(shù)字d數(shù)字w單詞W非單詞s空格S非空格.換行符以外的任意字符。這些斷言在字符

46、串中實際上匹配一個字符。正寬度意味著匹配一個字符,同時正則表達式引擎在匹配過程中“吃掉”它們。在表9-3中列出的負寬度斷言。這些斷言不是匹配一個字符,它們匹配的是一種條件。換句話講,cat匹配以cat開頭的字符串,但并不匹配任一給定字符。請看下面的表達式:mbziggurautb;mWziggurautW;$ziggurautString=thismatchesthewordzigguraut;$ziggurautString$ziggurautString9-3曲聲明字符串開頭$字符串結(jié)尾單詞邊界第一個例子匹配成功,因為它是在兩個非單詞字符(單詞邊界)之間查找ziggurat。而字;討山斡符

47、串滿足這種條件廠爛第二個例子沒有完成匹配,為什么呢?因為在末尾的W是寬度斷言,因此.必須匹配一個字符。但是在行未不是字符,而是一種條件。這是重要的區(qū)別。符。更進一步講,在第二個例子中即使實現(xiàn)了匹配,那么正則表達式引擎會消去涉及到的字因此,如果輸入如下代碼:$ziggurautString=Thismatchesthewordziggurautnow;$ziggurautString=sWziggurautWg;了。最后得到的結(jié)果是Thismatchesthewordnow原因是已經(jīng)把單詞和插入的空格替換掉因而:符。零寬度斷言,例如bB能匹配沒有字符的地方。它們在匹配的過程中不會去掉任一字下面是

48、關(guān)于通配符匹配的其他例子:$example=111119;$example=mddd;#matchthefirstthreedigitsitcanfindinthestringMatches111.$example=Thisisasetofwordsandnotofnumbers;$example=mof(wwwww);#Matchesofwords.Createsabackreference請注意最后一個例子,該列中,因為在字符串的開頭有一個Of(在words前面),所以模式匹配器會匹配這個特定的of。而不會去匹配后面的of(在numbers前面的那個)。最后一例也展示了我們討論論的問題。這

49、就是如果想匹配五個單詞字符的話,那么必須打印五次w,這樣就很煩惱。因此、為了便于匹配長模式,Perl提供了多重匹配運算符。我們接下來討論這個問題。2多重匹配運算符Perl中有六個多重匹配運算符。主要用于避免編寫重復(fù)代碼,例如上一節(jié)提到的在一行中聲明w五次。瀆者可把它們看作是速記的捷徑。PerI的六個多重匹配運算符是:*匹配零次,一次或多次。?匹配一次或者多次。?匹配零次或者一次。X匹配X次。X,匹配X或者更多次。X,Y匹配X到Y(jié)次。這里有兩個等價的例子,但是哪個易讀呢?$example=Thisisasetofwordsandnotofnumbers;$example=mof(wwwww);#

50、Matchesofword.$example=mof(w5);#UsageofXform.Matches5characters,#andbackreference$1becomesthestringwords.讀者可能發(fā)現(xiàn)第二個例子的代碼易讀。這個例子使用了多重匹配運算符來避免寫重復(fù)、討厭的代碼。第二個例子也用符號來匹配不定數(shù)量的字符。則表達式a*匹配”a,aa或者aaa,或任意數(shù)量的a。也就是匹配零個或多個a,例如:$example=thismatchesasetofwordsandnotofnumbers;$example=mof(w+);匹配的是字符串words(of(w+)eqofwo

51、rds),又如:$example=mof(w(2,3);#UsageofX,Y.Matchesthestringwor#(thefirstthreelettersofthefirstmatchitfinds.matchesthestringwor(ofw2,3equalsofworhere)與直覺相反.下面代碼中的m子句:$example=thismatchesasetofwordsandnotofnumbers;$example=mof(d*);匹配該字符串,盡管我們在用d*來查找數(shù)字。什么原因呢?因為d*表現(xiàn)為零個到多個,所以表達式匹配零個數(shù)字!然而:$example=mof(d+);不會

52、匹配相同的字符串,因為表達式使用的是d+而不是d*。這樣就意味著查找字符串中位于單詞of后面的一個或多個數(shù)字,而這種條件是這個字符串不具有的。3.貪婪到目前為止,上面所有的例子陳述主要的一點是正則表達式引擎如何按給定的表達式匹配給定的字符串。即缺省情況下,多重匹配運算符是貪婪地?!柏澙贰痹谶@里是什么含義呢?“貪婪”意味著在缺省狀態(tài)下,Perl的多重匹配運算符能捕獲一個字符串中的最大數(shù)量的字符,同的仍然有能力來完成模式匹配。讀者應(yīng)掌握好這一點。理解了貪婪的Perl表達式的本質(zhì)會節(jié)省大量時間,以免跟蹤古怪的正則表達式行為。這里有幾個簡單的關(guān)于貪婪行為的例子,例子中的貪婪行為能使程序員發(fā)瘋。讓我們從

53、下面的語句開始:$example=ThisisthebestexampleofthegreedypatternmatchinPerl5;假定在該例中想匹配is。相應(yīng)地,要編寫如下代碼:$example=m#This(.*)the#;print$1;#ThisdoesNOTprintoutthestringis!讀者希望打印$1時看到的是is。但是所得到的是下面的字符串:isthebestexampleof程序的工作過程如圖9-6所示。Example=Thisis(hebestexampleofthegreedypat優(yōu)mmatchinPerlV;Sexamplc=*mMThis(.*)tbe;

54、L_一一一一_-Sexample=BiiatsthebestcMwpleof皿撫hP*115(nThrc/*the;#bthHfbtlowvdbvtfierRfaiSeample-,tThi5httoebertexampitatugrwdypatternmatdiinpert5*;mThisC*)the*:*h陽bv血呼測Sexamplejmstfw&este*ampiriDeecee(iyRwtttmnutritidpe匕聖:Sewaple=ThishtbebestexampleofthegreedypatternnwtdiinoerlS;,is|bebeexampie匸勺造成這種結(jié)果的原因

55、是俵重匹配運算符*的貪婪。運算符*取得所有的字符直到最后出現(xiàn)的字符串the(在greedy前的一個)。那么如果讀者不小心,則在使用正則表達式后得到不可預(yù)料結(jié)果。這里有更samIam;m(.*)am;半aJChesthestringsamIRECORD:1VALUE:AVALUE2Fb70員雯+說明m.RECORD;(.*)VALUE;#matches1VALUE:A;RECORD;mw2,3;$example$example$example$example$example=#matchesREC$example最后一例顯示出甚至數(shù)字多重匹配運算符也是貪婪的。雖然在RECORD中有兩個單詞字符,

56、但是Perl更愿匹配三個,原因是它有這個能力。如果輸入RE=mw2,3,則只能匹配兩個字符,因為這是可能匹配的最大數(shù)量。4回溯和多重通配符好吧,已經(jīng)準備很久了現(xiàn)在到處理棘手題目的時候了。正如前面說過的,通配符和回溯的結(jié)合使正則表達式有極其緩慢的性能。如果讀者理解了其中的原因,那么這是讀者正“得到”正則表達式的好標志。看以下例子:$string=mhas(.*)multiple(.*)wildcards;這意味著正則表達式將查找(以數(shù)字順序):模式has(mhas.*multiple.*wildcards。)正則表達式能發(fā)現(xiàn)的最大文本直到它到達最后的multiple(mhas(.*)mMltip

57、le(.*)wildcards)。字符串multiple(mhas(.*)multiple(.*)wildcards。)能發(fā)現(xiàn)的最大文本直到遇到最后的wildcards(mhas(.*)multiple(.*)wildcards)。字符串wildcards(mhas(.*)multiple(.*)wildcards)。接著考慮一下,使用以下的模式將會發(fā)生什么:hasmanymultiplewildcardsmultipleWILDCARDS所發(fā)生的一切是:、Perl匹配has(i.e,mhas(.*)multiple(.*)wildcards);hasmanymultiplewildcards

58、multipleWILDCARDSPerl執(zhí)行mhas(.*)multiple(.*)wildcards部分且吃掉它能夠發(fā)現(xiàn)的所有字符,直到遇到最后的multiple,接著匹配:hasmanymultipIewildcardsmultipleWILDCARDSPerl匹配字符串multiple(即mhas(.*)multiple(.*)wildcards):hasmanymultiplewildcardsmultipleWILDCARDSPerl試圖發(fā)現(xiàn)字符串wildcards但是失敗了,接著讀出字符串的其余部分:WILDCARDSdoesnotmatchwildcards!現(xiàn)在Perl應(yīng)做什

59、么呢?因為有多個通配符(*),所以Perl回溯。正則表達式可能犯錯的地方是在第2步,即當(dāng)它吃掉:hasmanymultiplewildcardsmultipleWILDCARDS時,因而,它正好返回到has后面:hasmanymultiplewildcardsmultipleWILDCARDSgoesbackhere現(xiàn)在試圖更正錯誤,僅捕獲那些位于最后一個multiple之前的字符。因而,模式mhas(.*)multiple(.*)wildcards匹配:hasmanymultiplewildcardsmultipleWILDCARDS在mhas(.*)multiple(.*)wildcard

60、s中的multiple隨后匹配:hasmanymultiplewildcardsmultipleWILDCARDS接著通配符匹配空格mhas(.*)multiple(.*)wildcards匹配:hasmanymultiplewildcardsmultipleWILDCARDS最后,wildcards(mhas(.*)multiple(.*)wildcards匹配:hasmanymultiplewildcardsmultipleWILDCARDS因而整個正則表達式匹配hasmanymultiplewildcards。它給出了預(yù)料結(jié)果,但是得到該結(jié)果肯定走了彎路。肯定地說,Perl實施正則表達式

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論