主頁(yè) > 知識(shí)庫(kù) > 正則表達(dá)式的高級(jí)技巧分享

正則表達(dá)式的高級(jí)技巧分享

熱門(mén)標(biāo)簽:惠安地圖標(biāo)注 遼寧秒客來(lái)電話機(jī)器人 地圖標(biāo)注店鋪地圖標(biāo)注酒店 上海銷售電銷機(jī)器人軟件 哈爾濱公司外呼系統(tǒng)代理 自己做的電銷機(jī)器人 淄博市張店區(qū)地圖標(biāo)注 浙江營(yíng)銷外呼系統(tǒng)有哪些 山東外呼系統(tǒng)聯(lián)系方式
正則表達(dá)式(regular expression abbr. regex) 功能強(qiáng)大,能夠用于在一大串字符里找到所需信息。它利用約定俗成的字符結(jié)構(gòu)表達(dá)式來(lái)發(fā)生作用。不幸的是,簡(jiǎn)單的正則表達(dá)式對(duì)于一些高級(jí)運(yùn)用,功能遠(yuǎn)遠(yuǎn)不夠。若要進(jìn)行篩選的結(jié)構(gòu)比較復(fù)雜,你可能就需要用到高級(jí)正則表達(dá)式。

本文介紹正則表達(dá)式的高級(jí)技巧。篩選出了八個(gè)常用的概念,并配上實(shí)例解析,每個(gè)例子都是滿足某種復(fù)雜要求的簡(jiǎn)單寫(xiě)法。如果你對(duì)正則的基本概念尚缺乏了解,請(qǐng)先閱讀這篇文章,或者這個(gè)教程,或者維基條目。

這里的正則語(yǔ)法適用于php,與perl兼容。



1. 貪婪/懶惰


所有能多次限定的正則運(yùn)算符都是貪婪的。他們盡可能多地匹配目標(biāo)字符串,也就是說(shuō)匹配結(jié)果會(huì)盡可能地長(zhǎng)。不幸的是,這種做法并不總是我們想要的。因此,我們添加“懶惰”限定符來(lái)解決問(wèn)題。在各個(gè)貪婪運(yùn)算符后添加“?”能讓表達(dá)式只匹配盡可能短的長(zhǎng)度。另外,修改器“u”也能惰化能多次限定的運(yùn)算符。理解貪婪與懶惰的區(qū)別是運(yùn)用高級(jí)正則表達(dá)式的基礎(chǔ)。

貪婪操作符
操作符 匹配之前的表達(dá)式零次或零次以上。它是一個(gè)貪婪操作符。請(qǐng)看下面的例子:

復(fù)制代碼 代碼如下:

preg_match( ' / h1> . /h1> /' ' h1> 這是一個(gè)標(biāo)題。 /h1>
h1> 這是另一個(gè)。 /h1> ' $matches )

句點(diǎn)(.)能代表除換行符外的任意字符。上面的正則表達(dá)式匹配 h1 標(biāo)簽以及標(biāo)簽內(nèi)的所有內(nèi)容。它用句點(diǎn)(.)和星號(hào)()來(lái)匹配標(biāo)簽內(nèi)的所有內(nèi)容。匹配結(jié)果如下:

1. h1> 這是一個(gè)標(biāo)題。 /h1> h1> 這是另一個(gè)。 /h1>
整個(gè)字串都被返回。 操作符會(huì)連續(xù)匹配所有內(nèi)容—— 甚至包括中間的 h1 閉合標(biāo)簽。因?yàn)樗秦澙返模ヅ湔麄€(gè)字串是符合其利益最大化原則。

懶惰操作符
把上面的式子稍作修改,加上一個(gè)問(wèn)號(hào)(?),能讓表達(dá)式變懶惰:

1./ h1> .? /h1> /
這樣它會(huì)覺(jué)得,只需匹配到第一個(gè) h1 結(jié)尾標(biāo)簽就完成任務(wù)了。

另一個(gè)有著類似屬性的貪婪操作符是 {n } 。它代表之前的匹配模式重復(fù)n次或n次以上,如果沒(méi)有加上問(wèn)號(hào),它會(huì)尋找盡可能多的重復(fù)次數(shù),加上的話,則會(huì)盡可能少重復(fù)(當(dāng)然也就是“重復(fù)n次”最少)。


復(fù)制代碼 代碼如下:

# 建立字串
$str = ' hihihi oops hi'
# 使用貪婪的{n }操作符進(jìn)行匹配
preg_match( ' /(hi){2 }/' $str $matches ) # matches[0] 將是 ' hihihi'
# 使用墮化了的 {n }? 操作符匹配
preg_match( ' /(hi){2 }?/' $str $matches ) # matches[0] 將是 ' hihi'

2. 回返引用(back referencing)

有什么用?
回返引用(back referencing)一般被翻譯成“反向引用”、“后向引用”、“向后引用”,個(gè)人覺(jué)得“回返引用”更為貼切[笨活兒]。它是在正則表達(dá)式內(nèi)部引用之前捕獲到的內(nèi)容的方法。例如,下面這個(gè)簡(jiǎn)單例子的目的是匹配出引號(hào)內(nèi)部的內(nèi)容:

復(fù)制代碼 代碼如下:

# 建立匹配數(shù)組
$matches = array()

# 建立字串
$str = " " this is a ' string' " "

# 用正則表達(dá)式捕捉內(nèi)容
preg_match( " /(" |' ).?(" |' )/" $str $matches )

# 輸出整個(gè)匹配字串
echo $matches[0]

它會(huì)輸出:



1." this is a'
顯然,這并不是我們想要的內(nèi)容。

這個(gè)表達(dá)式從開(kāi)頭的雙引號(hào)開(kāi)始匹配,遭遇單引號(hào)之后就錯(cuò)誤地結(jié)束了匹配。這是因?yàn)楸磉_(dá)式里說(shuō):(”|'),也就是雙引號(hào)(”)和單引號(hào)(')均可。要修正這個(gè)問(wèn)題,你可以用到回返引用。表達(dá)式1 2 … 9 是對(duì)前面已捕獲到的各個(gè)子內(nèi)容的編組序號(hào),能作為對(duì)這些編組的“指針”而被引用。在此例中,第一個(gè)被匹配的引號(hào)就由 1 代表。

如何運(yùn)用?
將上面的例子中,后面的閉合引號(hào)替換為1:

1.preg_match( ' /(" |' ).?1/' $str $matches )
這會(huì)正確地返回字串:

1." this is a ' string' "
譯注思考題:

如果是中文引號(hào),前引號(hào)和后引號(hào)不是同一個(gè)字符,怎么辦?

還記得php函數(shù) preg_replace 嗎?其中也有回返引用。只不過(guò)我們沒(méi)有用 1 … 9,而是用了 $1 … $9 … $n (此處任意數(shù)目均可)作為回返指針。例如,如果你想把所有的段落標(biāo)簽 p> 都替換成文本:

復(fù)制代碼 代碼如下:

$text = preg_replace( ' / p> (.?) /p> /'
" lt p gt $1 lt /p gt " $html )

參數(shù)$1是一個(gè)回調(diào)引用,代表段落標(biāo)簽 p> 內(nèi)部的文字,并插入到替換后的文本里。這種簡(jiǎn)便易用的表達(dá)式寫(xiě)法為我們提供了一個(gè)獲取已匹配文字的簡(jiǎn)單方法,甚至在替換文本時(shí)也能使用。

3. 已命名捕獲組(named groups)
當(dāng)在一個(gè)表達(dá)式內(nèi)多次用到回調(diào)引用時(shí),很容易就把事情搞混淆,要弄清那些數(shù)字(1 … 9)都代表哪一個(gè)子內(nèi)容是件很麻煩的事?;卣{(diào)引用的一個(gè)替代方法是使用帶名字的捕獲組(下文簡(jiǎn)稱“有名組”)。有名組使用(?p name> pattern)來(lái)設(shè)定,name代表組名,pattern是配合該有名組的正則結(jié)構(gòu)。請(qǐng)看下面的例子:

1./(?p quote> " |' ).?(?p=quote)/
上式中,quote就是組名,”|' 的是匹配內(nèi)容的正則。后面的(?p=quote)是在調(diào)用組名為quote的有名組。這個(gè)式子的效果和上面的回調(diào)引用實(shí)例一樣,只不過(guò)是用了有名組來(lái)實(shí)現(xiàn)。是不是更加易讀易懂了?

有名組也能用于處理已匹配內(nèi)容之?dāng)?shù)組的內(nèi)部數(shù)據(jù)。賦予特定正則的組名也能作為所匹配到的內(nèi)容在數(shù)組內(nèi)部的索引詞。

復(fù)制代碼 代碼如下:

preg_match( ' /(?p quote> " |' )/' " ' string' " $matches )

# 下面的語(yǔ)句輸出“' ”(不包括雙引號(hào))
echo $matches[1]

# 使用組名調(diào)用,也會(huì)輸出“' ”
echo $matches[' quote' ]

所以,有名組并不只是讓寫(xiě)代碼更容易,它也能用于組織代碼。

4. 字詞邊界(word boundaries)

字詞邊界是字串里的字詞字符(包括字母、數(shù)字和下劃線,自然也包括漢字)和非字詞字符之間的位置。其特殊之處就在于,它并不匹配某個(gè)實(shí)在的字符。它的長(zhǎng)度是零。 b 匹配所有字詞邊界。

不幸的是,字詞邊界一般都被忽視掉了,大部分人都沒(méi)有在意他的現(xiàn)實(shí)意義。 例如,如果你想要匹配單詞“import”:

1./import/
注意了!正則表達(dá)式有時(shí)候很調(diào)皮的。下面的字串也能和上面的式子匹配成功:

1.important
你或許覺(jué)得,只要在import前后加上空格,不就可以匹配這個(gè)獨(dú)立的單詞了:

1./ import /
那如果遇上這種情況呢:

1.the trader voted for the import
當(dāng) import 這個(gè)詞在字串開(kāi)頭或者結(jié)尾時(shí),修改后的表達(dá)式仍然不能用。因此,考慮各種情況是必須的:

1./(^import | import | import$)/i
別慌,還沒(méi)完呢。如果遇到標(biāo)點(diǎn)符號(hào)了呢?就為了滿足這一個(gè)單詞的匹配,你的正則可能就需要這樣寫(xiě):

1./(^import(:| | )? | import(:| | )? | import(.|?|!)?$)/i
對(duì)于只匹配一個(gè)單詞來(lái)說(shuō),這樣做實(shí)在是有點(diǎn)大動(dòng)干戈了。正因如此,字詞邊界才顯得意義重大。要適應(yīng)上述要求,以及很多其他情況變種,有了字符邊界,我們所需寫(xiě)的代碼只是:

1./bimportb/
上面所有情況都得到了解決。 b 的靈活性就在于,它是一個(gè)沒(méi)有長(zhǎng)度的匹配。它只匹配兩個(gè)實(shí)際字符之間想象出的位置。它檢查兩個(gè)相鄰字符是否是一個(gè)為單字,另一個(gè)為非單字。情況符合,就返回匹配。如果遇到了單詞的開(kāi)頭或結(jié)尾, b 會(huì)把它當(dāng)成是非單詞字符對(duì)待。由于import里面的 i 仍然被看成是單詞字符,import 就被匹配出來(lái)了。

注意,與b相對(duì),我們還有 b,此操作符匹配兩個(gè)單字或者兩個(gè)非單字之間的位置。因此,如果你想匹配在某個(gè)單詞內(nèi)部的‘hi',可以使用:

1.bhib
“this”、“hight”,都會(huì)返回匹配,而“hi there”則會(huì)返回不匹配。

5. 最小組團(tuán)(atomic groups)

最小組團(tuán)是無(wú)捕捉的特殊正則表達(dá)式分組。通常用來(lái)提高正則表達(dá)式的效能,也能用于消除特定匹配。一個(gè)最小組團(tuán)可以用(?> pattern) 來(lái)定義,其中pattern是匹配式。

1./(?> his|this)/
當(dāng)正則引擎針對(duì)最小組團(tuán)進(jìn)行匹配時(shí),它會(huì)跳過(guò)組團(tuán)內(nèi)標(biāo)記的回溯位置。以單詞“smashing”為例,當(dāng)用上面的正則表達(dá)式匹配時(shí),正則引擎會(huì)先嘗 試在“smashing”里尋找“his”。顯然,找不到任何匹配。此時(shí),最小組團(tuán)就發(fā)揮作用了:正則引擎會(huì)放棄所有回溯位置。也就是說(shuō),它不會(huì)嘗試再?gòu)?“smashing”里查找“this”。為什么要這樣設(shè)置?因?yàn)椤癶is”都沒(méi)有返回匹配結(jié)果,包含有“his”的“this”當(dāng)然就更匹配不了了!

上面的例子并沒(méi)有什么實(shí)用性,我們用/t?his?/ 也能達(dá)到效果。再看看下面的例子:

1./b(engineer|engrave|end)b/
如果把“engineering”拿去匹配,正則引擎會(huì)先匹配到“engineer”,但接下來(lái)就遇到了字詞邊界,b,所以匹配不成功。然后,正則 引擎又會(huì)嘗試在字串里尋找下一個(gè)匹配內(nèi)容:engrave。匹配到eng的時(shí)候,后面的又對(duì)不上了,匹配失敗。最后,嘗試“end”,結(jié)果同樣是失敗。仔 細(xì)觀察,你會(huì)發(fā)現(xiàn),一旦engineer匹配失敗,并且都抵達(dá)了字詞邊界,“engrave”和“end”這兩個(gè)詞就已經(jīng)不可能匹配成功了。這兩個(gè)詞都比 engineer短小,正則引擎不應(yīng)該再多做無(wú)謂的嘗試。

1./b(?> engineer|engrave|end)b/
上面的替代寫(xiě)法更能節(jié)省正則引擎的匹配時(shí)間,提高代碼的工作效率。

6. 遞歸(recursion)

遞歸(recursion)用于匹配嵌套結(jié)構(gòu),例如括弧嵌套, (this (that)),html標(biāo)簽嵌套 div> div> /div> /div> 。我們使用(?r)來(lái)代表遞歸過(guò)程中的子模式。下面是一個(gè)匹配嵌套括弧的例子:

1./(((?> [^()]+)|(?r)))/
最外層使用了反義符的括號(hào)“(”匹配嵌套結(jié)構(gòu)的開(kāi)端。然后是一個(gè)多選項(xiàng)操作符( | ),可能匹配除括號(hào)外的所有字符 “(?> [^()]+)”,也可能是通過(guò)子模式“(?r)”來(lái)再次匹配整個(gè)表達(dá)式。請(qǐng)注意,這個(gè)操作符會(huì)盡量多地匹配所有嵌套。

遞歸的另一個(gè)實(shí)例如下:

1./ ([w]+).?> ((?> [^ > ]+)|((?r))) /1> /
以上表達(dá)式綜合運(yùn)用了字符分組,貪婪操作符、回溯,以及最小化組團(tuán)來(lái)匹配嵌套標(biāo)簽。第一個(gè)括弧內(nèi)分組([w]+)匹配出標(biāo)簽名,用于接下來(lái)的應(yīng)用。若找到這尖括號(hào)樣式的標(biāo)簽,則嘗試尋找標(biāo)簽內(nèi)容的剩余部分。下一個(gè)括弧括起來(lái)的子表達(dá)式和上一個(gè)實(shí)例非常相似:要么匹配不包括尖括號(hào)的所有字符 (?> [^ > ]+),要么遞歸匹配整個(gè)表達(dá)式(?r)。整個(gè)表達(dá)式最后一部分就是尖括號(hào)樣式的閉合標(biāo)簽 /1> 。

7. 回調(diào)(callbacks)

匹配結(jié)果中的特定內(nèi)容有時(shí)可能會(huì)需要某種特別的修改。要應(yīng)用多重而復(fù)雜的修改,正則表達(dá)式的回調(diào)就有了用武之地?;卣{(diào)是用于函數(shù)preg_replace_callback中的動(dòng)態(tài)修改字串的方式。你可以為preg_replace_callback指定某個(gè)函數(shù)為參數(shù),此函數(shù)能接收匹配結(jié)果數(shù)組為參數(shù),并將數(shù)組修改后返回,作為替換的結(jié)果。

例如,我們想將某字串中的字母全部轉(zhuǎn)變成大寫(xiě)。十分不巧,php沒(méi)有直接轉(zhuǎn)化字母大小寫(xiě)的正則操作符。要完成這項(xiàng)任務(wù),就可以用到正則回調(diào)。首先,表達(dá)式要匹配出所有需要被大寫(xiě)的字母:

1./bw/
上式同時(shí)使用了字詞邊界和字符類。光有這個(gè)式子還不夠,我們還需要一個(gè)回調(diào)函數(shù):
復(fù)制代碼 代碼如下:

function upper_case( $matches ) {
return strtoupper( $matches[0] )
}

函數(shù)upper_case接收匹配結(jié)果數(shù)組,并將整個(gè)匹配結(jié)果轉(zhuǎn)化成大寫(xiě)。 在此例中,$matches[0]代表需要被大寫(xiě)化的字母。然后,我們?cè)倮胮reg_replace_callback實(shí)現(xiàn)回調(diào):

1.preg_replace_callback( ' /bw/' " upper_case" $str )
一個(gè)簡(jiǎn)單的回調(diào)即有這般強(qiáng)大的力量。

8. 注釋(commenting)

注釋不用來(lái)匹配字串,但確實(shí)是正則表達(dá)式中最重要的部分。當(dāng)正則越寫(xiě)越深入,越寫(xiě)越復(fù)雜,要推譯出究竟什么東西被匹配就會(huì)變得越來(lái)越困難。在正則表達(dá)式中間加上注釋,是最小化將來(lái)的迷糊和困惑的最佳方式。

要在正則表達(dá)式內(nèi)部加上注釋,使用(?#comment)格式。把“comment”替換成你的注釋語(yǔ)句:

1./(?#數(shù)字)d/
如果你打算把代碼公之于眾,為正則表達(dá)式加上注釋就顯得尤為重要。這樣別人才能更容易看懂和修改你的代碼。和其他場(chǎng)合的注釋一樣,這樣做也能為你重訪自己以前寫(xiě)的程序時(shí)提供方便。

考慮使用“x”或“(?x)”修改器來(lái)格式化注釋。這個(gè)修改器讓正則引擎忽略表達(dá)式參數(shù)之間的空格?!坝杏玫摹笨崭袢匀荒軌蛲ㄟ^(guò)[ ]或(反義符加空格)來(lái)匹配。

復(fù)制代碼 代碼如下:

/
d #digit
[ ] #space
w+ #word
/x

上面的代碼與下面的式子作用一樣:

1./d(?#digit)[ ](?#space)w+(?#word)/
請(qǐng)時(shí)刻注意代碼的可讀性。

模式修正符
是為正則表達(dá)式增強(qiáng)和補(bǔ)充的一個(gè)功能,使用在正則之外
例子:/正則/U U就表示一個(gè)模式修正符
一下幾個(gè)為php中常用的:(注意:區(qū)分大小寫(xiě))
i 正則內(nèi)容在匹配時(shí)候不區(qū)分大小寫(xiě)(默認(rèn)是區(qū)分的)
m 在匹配首內(nèi)容或者尾內(nèi)容時(shí)候采用多行識(shí)別匹配
s 將轉(zhuǎn)義回車取消是為單位匹配

x 忽略正則中的空白
A 強(qiáng)制從頭開(kāi)始匹配
D 強(qiáng)制$匹配尾部任何內(nèi)容\n
U 禁止貪mei匹配,只跟蹤到最近的一個(gè)匹配符并結(jié)束,常用在采集程序的正則表達(dá)式
您可能感興趣的文章:
  • 正則表達(dá)式高級(jí)學(xué)習(xí)技巧
  • ASP正則表達(dá)式技巧
  • PHP 正則表達(dá)式的幾則使用技巧
  • 正則表達(dá)式高級(jí)技巧及實(shí)例詳解 笨活兒
  • javascript 正則表達(dá)式(二) 使用技巧說(shuō)明
  • 模板引擎正則表達(dá)式調(diào)試小技巧
  • .NET 正則表達(dá)式使用高級(jí)技巧之替換類介紹
  • 正則表達(dá)式匹配不包含某些字符串的技巧
  • 寫(xiě)出高效率的正則表達(dá)式技巧總結(jié)

標(biāo)簽:西安 長(zhǎng)沙 宣城 綿陽(yáng) 無(wú)錫 重慶 銅川 泰州

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《正則表達(dá)式的高級(jí)技巧分享》,本文關(guān)鍵詞  正則,表達(dá)式,的,高級(jí),技巧,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問(wèn)題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無(wú)關(guān)。
  • 相關(guān)文章
  • 下面列出與本文章《正則表達(dá)式的高級(jí)技巧分享》相關(guān)的同類信息!
  • 本頁(yè)收集關(guān)于正則表達(dá)式的高級(jí)技巧分享的相關(guān)信息資訊供網(wǎng)民參考!
  • 推薦文章