正則表達式高級技巧及實例詳解_第1頁
正則表達式高級技巧及實例詳解_第2頁
正則表達式高級技巧及實例詳解_第3頁
正則表達式高級技巧及實例詳解_第4頁
正則表達式高級技巧及實例詳解_第5頁
全文預覽已結(jié)束

下載本文檔

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

文檔簡介

正則表達式高級技巧及實例詳解正則表達式(RegularExpression,abbr.regex)功能強大,能夠用于在一大串字符里找到所需信息。它利用約定俗成的字符結(jié)構(gòu)表達式來發(fā)生作用。不幸的是,簡單的正則表達式對于一些高級運用,功能遠遠不夠。若要進行篩選的結(jié)構(gòu)比較復雜,你可能就需要用到高級正則表達式。本文為您介紹正則表達式的高級技巧。我們篩選出了八個常用的概念,并配上實例解析,每個例子都是滿足某種復雜要求的簡單寫法。如果你對正則的基本概念尚缺乏了解,請先閱讀這篇文章,或者這個教程,或者維基條目這里的正則語法適用于PHP,與Perl兼容。1.貪婪/懶惰所有能多次限定的正則運算符都是貪婪的。他們盡可能多地匹配目標字符串,也就是說匹配結(jié)果會盡可能地長。不幸的是,這種做法并不總是我們想要的。因此,我們添加“懶惰”限定符來解決問題。在各個貪婪運算符后添加“?”能讓表達式只匹配盡可能短的長度。另外,修改器“U”也能惰化能多次限定的運算符。理解貪婪與懶惰的區(qū)別是運用高級正則表達式的基礎。貪婪操作符操作符*匹配之前的表達式零次或零次以上。它是一個貪婪操作符。請看下面的例子:preg_match('/<h1>.*<\/h1>/','<h1>這是一個標題。</h1><h1>這是另一個。</h1>',$matches);句點(.)能代表除換行符外的任意字符。上面的正則表達式匹配h1標簽以及標簽內(nèi)的所有內(nèi)容。它用句點(.)和星號(*)來匹配標簽內(nèi)的所有內(nèi)容。匹配結(jié)果如下:<h1>這是一個標題。</h1><h1>這是另一個。</h1>整個字串都被返回。*操作符會連續(xù)匹配所有內(nèi)一一甚至包括中間的h1閉合標簽。因為它是貪婪的,匹配整個字串是符合其利益最大化原則。懶惰操作符把上面的式子稍作修改,加上一個問號(?),能讓表達式變懶惰:/<h1>.*?<\/h1>/這樣它會覺得,只需匹配到第一個hl結(jié)尾標簽就完成任務了。另一個有著類似屬性的貪婪操作符是{n,}。它代表之前的匹配模式重復n次或n次以上,如果沒有加上問號,它會尋找盡可能多的重復次數(shù),加上的話,則會盡可能少重復(當然也就是“重復n次”最少)。#建立字串$str='hihihioopshi';#使用貪婪的{n,}操作符進行匹配preg_match('/(hi){2,}/',$str,$matches);#matches[0]將是'hihihi'#使用墮化了的{n,}?操作符匹配preg_match('/(hi){2,}?/',$str,$matches);#matches[0]將是'hihi'回返引用(Backreferencing)有什么用?回返引用(Backreferencing)一般被翻譯成“反向引用”、“后向引用”、“向后引用”,個人覺得“回返引用”更為貼切[笨活兒]。它是在正則表達式內(nèi)部引用之前捕獲到的內(nèi)容的方法。例如,下面這個簡單例子的目的是匹配出引號內(nèi)部的內(nèi)容:#建立匹配數(shù)組$matches=array();#建立字串$str=""Thisisa'string'"”;#用正則表達式捕捉內(nèi)容preg_match("/(\"|').*?(\"|')/",$str,$matches);#輸出整個匹配字串echo$matches[0];它會輸出:"Thisisa'顯然,這并不是我們想要的內(nèi)容。這個表達式從開頭的雙引號開始匹配,遭遇單引號之后就錯誤地結(jié)束了匹配。這是因為表達式里說:("|'),也就是雙引號(")和單引號(')均可。要修正這個問題,你可以用到回返引用。表達式\1,\2,...,\9是對前面已捕獲到的各個子內(nèi)容的編組序號,能作為對這些編組的“指針”而被引用。在此例中,第一個被匹配的引號就由\1代表。如何運用?將上面的例子中,后面的閉合引號替換為1:preg_match('/(\"|').*?\1/',$str,$matches);這會正確地返回字串:"Thisisa'string'"如果是中文引號,前引號和后引號不是同一個字符,怎么辦?還記得PHP函數(shù)preg_replace嗎?其中也有回返引用。只不過我們沒有用\1...\9,而是用了$1...$9...$n(此處任意數(shù)目均可)作為回返指針。例如,如果你想把所有的段落標簽<p>都替換成文本:$text=preg_replace('/<p>(.*?)</p>/',"<p>$1</p>",$html);參數(shù)$1是一個回返引用,代表段落標簽<p>內(nèi)部的文字,并插入到替換后的文本里。這種簡便易用的表達式寫法為我們提供了一個獲取已匹配文字的簡單方法,甚至在替換文本時也能使用。己命名捕獲組(NamedGroups)當在一個表達式內(nèi)多次用到回調(diào)引用時,很容易就把事情搞混淆,要弄清那些數(shù)字(1...9)都代表哪一個子內(nèi)容是件很麻煩的事?;卣{(diào)引用的一個替代方法是使用帶名字的捕獲組(下文簡稱“有名組”)。有名組使用(?P<name>pattern)來設定,name代表組名,pattern是配合該有名組的正則結(jié)構(gòu)。請看下面的例子:/(?P<quote>"|').*?(?P=quote)/上式中,quote就是組名,"|'是改組匹配內(nèi)容的正則。后面的(?P=quote)是在調(diào)用組名為quote的有名組。這個式子的效果和上面的回調(diào)引用實例一樣,只不過是用了有名組來實現(xiàn)。是不是更加易讀易懂了?有名組也能用于處理已匹配內(nèi)容之數(shù)組的內(nèi)部數(shù)據(jù)。賦予特定正則的組名也能作為所匹配到的內(nèi)容在數(shù)組內(nèi)部的索引詞。preg_match('/(?P<quote>"|\')/',"'String'",$matches);#下面的語句輸出“'”(不包括雙引號)echo$matches[1];#使用組名調(diào)用,也會輸出“'”echo$matches['quote'];所以,有名組并不只是讓寫代碼更容易,它也能用于組織代碼。字詞邊界(WordBoundaries)字詞邊界是字串里的字詞字符(包括字母、數(shù)字和下劃線,自然也包括漢字)和非字詞字符之間的位置。其特殊之處就在于,它并不匹配某個實在的字符。它的長度是零。\b匹配所有字詞邊界。不幸的是,字詞邊界一般都被忽視掉了,大部分人都沒有在意他的現(xiàn)實意義。例如,如果你想要匹配單詞“import”:/import/注意了!正則表達式有時候很調(diào)皮的。下面的字串也能和上面的式子匹配成功:important你或許覺得,只要在import前后加上空格,不就可以匹配這個獨立的單詞了:/import/那如果遇上這種情況呢:Thetradervotedfortheimport當import這個詞在字串開頭或者結(jié)尾時,修改后的表達式仍然不能用。因此,考慮各種情況是必須的:/(^import|import|import$)/i別慌,還沒完呢。如果遇到標點符號了呢?就為了滿足這一個單詞的匹配,你的正則可能就需要這樣寫:/(Aimport(:|;|,)?|import(:|;|,)?|import(\.|\?|\!)?$)/i對于只匹配一個單詞來說,這樣做實在是有點大動干戈了。正因如此,字詞邊界才顯得意義重大。要適應上述要求,以及很多其他情況變種,有了字符邊界,我們所需寫的代碼只是:八bimport\b/上面所有情況都得到了解決。\b的靈活性就在于,它是一個沒有長度的匹配。它只匹配兩個實際字符之間想象出的位置。它檢查兩個相鄰字符是否是一個為單字,另一個為非單字。情況符合,就返回匹配。如果遇到了單詞的開頭或結(jié)尾,\b會把它當成是非單詞字符對待。由于import里面的i仍然被看成是單詞字符,import就被匹配出來了。注意,與\b相對,我們還有\(zhòng)B,此操作符匹配兩個單字或者兩個非單字之間的位置。因此,如果你想匹配在某個單詞內(nèi)部的'hi',可以使用:\Bhi\B“this”、“hight”,都會返回匹配,而“hithere”則不會返回匹配。最小組團(AtomicGroups)最小組團是無捕捉的特殊正則表達式分組。通常用來提高正則表達式的效能,也能用于消除特定匹配。一個最小組團可以用(?>pattern)來定義,其中pattern是匹配式。/(?>his|this)/當正則引擎針對最小組團進行匹配時,它會跳過組團內(nèi)標記的回溯位置。以單詞“smashing”為例,當用上面的正則表達式匹配時,正則引擎會先嘗試在“smashing”里尋找“his”。顯然,找不到任何匹配。此時,最小組團就發(fā)揮作用了:正則引擎會放棄所有回溯位置。也就是說,它不會嘗試再從“smashing”里查找“this”。為什么要這樣設置?因為“his”都沒有返回匹配結(jié)果,包含W“his”的“this”當然就更匹配不了了!上面的例子并沒有什么實用性,我們用/t?his?/也能達到效果。再看看下面的例子:/\b(engineer|engrave|end)\b/如果把“engineering”拿去匹配,正則引擎會先匹配到“engineer”,但接下來就遇到了字詞邊界,\b,所以匹配不成功。然后,正則引擎又會嘗試在字串里尋找下一個匹配內(nèi)容:engraveo匹配到eng的時候,后面的又對不上了,匹配失敗。最后,嘗試“end”,結(jié)果同樣是失敗。仔細觀察,你會發(fā)現(xiàn),一旦engineer匹配失敗,并且都抵達了字詞邊界,“engrave”和“end”這兩個詞就已經(jīng)不可能匹配成功了。這兩個詞都比engineer短小,正則引擎不應該再多做無謂的嘗試。/\b(?>engineer|engrave|end)\b/上面的替代寫法更能節(jié)省正則引擎的匹配時間,提高代碼的工作效率。遞歸(Recursion)遞歸(Recursion)用于匹配嵌套結(jié)構(gòu),例如括弧嵌套,(this(that)),HTML標簽嵌套<div><div></div></div>。我們使用(?R)來代表遞歸過程中的子模式。下面是一個匹配嵌套括弧的例子:八(((?>F()]+)|(?R))*\)/最外層使用了反義符的括號“\(”匹配嵌套結(jié)構(gòu)的開端。然后是一個多選項操作符(*|*),可能匹配除括號外的所有字符“(?>[△()]+)”,也可能是通過子模式“(?R)”來再次匹配整個表達式。請注意,這個操作符會盡量多地匹配所有嵌套。遞歸的另一個實例如下:/<([\w]+).*?>((?>[A<>]+)|((?R)))*<\八1>/以上表達式綜合運用了字符分組,貪婪操作符、回溯,以及最小化組團來匹配嵌套標簽。第一個括弧內(nèi)分組([w]+)匹配出標簽名,用于接下來的應用。若找到這尖括號樣式的標簽,則嘗試尋找標簽內(nèi)容的剩余部分。下一個括弧括起來的子表達式和上一個實例非常相似:要么匹配不包括尖括號的所有字符?>[八<>]+,要么遞歸匹配整個表達式(?R)。表達式最后的</1>代表閉合標簽?;卣{(diào)(Callbacks)匹配結(jié)果中的特定內(nèi)容有時可能會需要某種特別的修改。要應用多重而復雜的修改,正則表達式的回調(diào)就有了用武之地?;卣{(diào)是用于函數(shù)preg_replace_callback中的動態(tài)修改字串的方式。你可以為preg_replace_callback指定某個函數(shù)為參數(shù),此函數(shù)能接收匹配結(jié)果數(shù)組為參數(shù),并將數(shù)組修改后返回,作為替換的結(jié)果。例如,我們想將某字串中的字母全部轉(zhuǎn)變成大寫。十分不巧,PHP沒有直接轉(zhuǎn)化字母大小寫的正則操作符。要完成這項任務,就可以用到正則回調(diào)。首先,表達式要匹配出所有需要被大寫的字母:八b\w/上式同時使用了字詞邊界和字符類。光有這個式子還不夠,我們還需要一個回調(diào)函數(shù):functionupper_case($matches){returnstrtoupper($matches[0]);}函數(shù)upper_case接收匹配結(jié)果數(shù)組,并將整個匹配結(jié)果轉(zhuǎn)化成大寫。在此例中,$matches[0]代表需要被大寫化的字母。然后,我們再利用preg_replace_callback實現(xiàn)回調(diào):preg_replace_callback('八b\w/',"upper_case",$str);一個簡單的回調(diào)即有這般強大的力量。注釋(Commenting)注釋不用來匹配字串,但確實是正則表達式中最重要的部分。當正則越寫越深入,越寫越復雜,要推譯出究竟什么東西被匹配就會變得越來越困難。在正則表達式中間加上注釋,是最小化將來的迷糊和困惑的最佳方式。要在正則表達式內(nèi)部加上注釋,使用(?#comment)格式。把“comment”替換成你

溫馨提示

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

評論

0/150

提交評論