前文中,已經(jīng)總結(jié)了正則表達(dá)式中的常用字符、次數(shù)匹配、位置匹配等,這篇文章中,我們來了解一下正則中的"分組"與"后向引用"。
什么是分組?什么是后向引用?我們慢慢聊。
先來說說什么是分組。 算了,思考了半天,我也不知道從何說起,先看個示例吧,根據(jù)示例去描述反而更加清晰,示例如下。
上述示例中,我們使用到了之前所了解到的"連續(xù)次數(shù)匹配","\{2\}"表示其前面的字符連續(xù)出現(xiàn)的2次,即可被匹配到。 但是,正如上圖所示,"\{2\}"所影響的字符只是其前面的單個字符,也就是上例中的字母o 所以,上例中,helloo被匹配到了,hellooo也被匹配到了,因?yàn)?hell"字符串后面的確出現(xiàn)了2次字母o
但是,如果我們想要從上例中的文本中找出,2次連續(xù)出現(xiàn)的hello字符串,該怎么辦呢? 正如你所看到的,"hello\{2\}"并不能表示"hellohello",它只能表示"helloo",那么,我們該怎么辦呢? 這個時候,我們就需要用到"分組",將"hello"當(dāng)做一個"分組",當(dāng)做一個"整體",才可以達(dá)到我們的目的,示例如下
正如上圖所示,"\(hello\)"表示將hello字符串當(dāng)做一個整體,所以,"\{2\}"所影響的字符就是前面的"hello字符串"(這個整體)。 所以,"\(hello\)\{2\}"這個正則表達(dá)式就表示hello字符串連續(xù)出現(xiàn)兩次,也就是"hellohello" 沒錯,"\( \)"就表示分組。 "\( \)"表示將其中的內(nèi)容看做一個分組,看做一個整體。
分組還可以嵌套,什么意思呢?我們來看一個例子。
上圖中的正則表達(dá)式猛一看有些復(fù)雜,但是我們一點(diǎn)一點(diǎn)的拆開來看,就比較容易理解了,沒錯,我們先按照上圖所示,將"紅線部分"與"藍(lán)線部分"拆成兩部分 藍(lán)線部分為"\{2\}",表示之前的字符連續(xù)出現(xiàn)兩次 紅線部分為"\(ab\(ef\)\{2\}\)",可以看到,紅線部分的兩側(cè)正好由"\( \)"組成,由此可見,紅線部分應(yīng)該作為一個整體,應(yīng)該作為一個分組被操作,再結(jié)合之前的藍(lán)線部分,即可得知,紅線部分應(yīng)該作為一個整體連續(xù)出現(xiàn)兩次。 那么,我們把紅線部分最外側(cè)的"\( \)"去掉,紅線部分內(nèi)側(cè)的正則為"ab\(ef\)\{2\}",可以看到,紅線部分內(nèi)側(cè)的正則中還有一組分組符號,就是"\(ef\)",這個分組符號把ef當(dāng)做了一個整體,所以,"ab\(ef\)\{2\}"表示字符串a(chǎn)b后面跟隨了2個連續(xù)出現(xiàn)的ef,那么,"ab\(ef\)\{2\}"就表示字符串"abefef"。 逆推回去,我們把紅線內(nèi)側(cè)的正則替換為"abefef",于是,上例中的正則就表示"\(abefef\)\{2\}",最終如上圖所示,2次連續(xù)出現(xiàn)的abefef被匹配到了。 上例中,紅線部分一共包含兩個分組符號,最外側(cè)的"\( \)"中又包含了另一個"\( \)",這就是分組符號的嵌套。
我想,我應(yīng)該說清楚了。
那么,我們再來聊聊什么是后向引用。 之所以先介紹分組,是因?yàn)楹笙蛞檬且苑纸M為前提的,如果想要實(shí)現(xiàn)后向引用,則必須先進(jìn)行分組。 那么"后向引用"是什么意思呢? 如果直接放出概念,我不容易描述,你也不容易理解,我們還是先來看個小例子吧,示例文件如下。
如果我們想要使用正則去匹配上述示例中的兩行文本,我們改怎么辦呢? 我們可以使用如下正則表達(dá)式去匹配。
"H.\{4\}"表示大寫字母H的后面跟隨了4個任意字符,其中"."表示任意單個字符,我們在前文中已經(jīng)舉例演示過,此處不再贅述。 所以,"H.\{4\}"既可以匹配到Hello,也可以匹配到Hiiii,那么,上述兩行文本都被匹配到了。
此時,我們修改一下示例文件,在示例文件中再添加一行測試文本,修改后的測試文件內(nèi)容如下
如上圖所示,我們添加了一行文本,這行文本以Hello開頭,以Hiiii結(jié)尾。 我們使用剛才的正則,能夠匹配到這一行新添加的文本嗎,我們來試試。
可以看到,新添加的一行文本也被匹配到了,因?yàn)?H.\{4\}"表示大寫字母H的后面跟隨了4個任意字符,最后一行也滿足條件,所以也被匹配到了。
但是此刻,我有了新需求~~ 我只想從上例中找出"world"前后單詞相同的那些行,換句話說就是,world之前的單詞是Hello,world之后的單詞也要是Hello,world之前的單詞是Hiiii,world之后的單詞也要是Hiiii,只有這種行滿足條件。 上例中第三行則不滿足條件,因?yàn)樯侠牡谌兄?,world之前的單詞是Hello,而world之后的單詞是Hiiii,前后不一致,所以不滿足我的條件。 那么我該怎么辦呢?之前的正則肯定不行,因?yàn)橹暗恼齽t也能夠?qū)⑸侠械牡谌衅ヅ涞健?/p> 這個時候,就需要用到"后向引用",示例如下。
可以看到,使用上述正則,即可達(dá)到我們的目的,只有world前后的單詞完全相同時,才會被匹配到。 那么,上例中的正則是什么意思呢?我們?nèi)匀徊鸪蓛刹糠謥斫榻B,以便我們理解。 上例的紅線部分為:"\(H.\{4\}\)" 上例的藍(lán)線部分為:"\1"
紅線部分的正則與之前示例中的正則只有一點(diǎn)點(diǎn)區(qū)別,就是在原來的基礎(chǔ)之上添加了分組,將"H.\{4\}"變成了"\(H.\{4\}\)",但是它的大概含義并沒有改變,"\(H.\{4\}\)"表示大寫字母H的后面跟隨了4個任意字符,并且字母H與后面的4個字符將作為一個整體。那么,為什么要在原來的基礎(chǔ)上添加分組呢?這是因?yàn)?,如果想要?shí)現(xiàn)后向應(yīng)用,則必須以分組為前提,現(xiàn)在我們暫且不糾結(jié)這一點(diǎn),之后回過頭來看,就會明白。
藍(lán)色部分的正則為"\1",它有什么含義呢? "\1"表示整個正則中第1個分組中的正則所匹配到的結(jié)果,這樣說可能不容易理解,我們用大白話說一遍。 在上例中,整個正則中只出現(xiàn)了1個分組,就是"\(H.\{4\}\)",當(dāng)它與示例文件中的第一行文本進(jìn)行匹配時,會匹配到Hello字符串,這時,"\1"就表示Hello字符串。 當(dāng)正則"\(H.\{4\}\)"與示例文件中的第二行文本進(jìn)行匹配時,會匹配到Hiiii字符串,這時,"\1"就表示Hiiii字符串。 也就是說,"\1"必須與整個正則中第1個分組中的正則(也就是紅色部分的正則)所匹配到的結(jié)果相同。 換句話說就是,"\1"引用了整個正則中第1個分組中的正則(也就是紅色部分的正則)所匹配到的結(jié)果。 如果你還沒有懂,看圖理解吧。
現(xiàn)在回頭想想,你知道為什么必須為"H.\{4\}"添加分組了嗎?因?yàn)椋?dāng)我們?yōu)?H.\{4\}"添加了分組以后,"H.\{4\}"就變成了整個正則中第1個分組中的正則,當(dāng)"H.\{4\}"匹配到的結(jié)果為Hello時,"\1"就引用了Hello,當(dāng)"H.\{4\}"匹配到的結(jié)果為Hiiii時,"\1"就引用了Hiiii。
這就是所謂的"后向引用"。 上述描述看一遍可能不容易立馬理解,可以重復(fù)仔細(xì)的多看幾遍,慢慢就會理解了。
聰明如你,一定想到了。 "\1"表示引用整個正則中第1個分組中的正則所匹配到的結(jié)果,那么,"\2"呢?沒錯,正如你所想。 "\2"表示引用整個正則中第2個分組中的正則所匹配到的結(jié)果 示例如下
如上圖所示,"\2"引用了上圖中"綠線部分的正則"所匹配到的結(jié)果,而上圖中"綠線部分的正則"就是"整個正則表達(dá)式中第2個分組中的正則"。
那么,以此類推,"\3"、"\4"、"\5"、"\6"所表達(dá)的意思就不言而喻了。 再次強(qiáng)調(diào),使用后向引用的前提是將需要引用的部分分組。
不過,當(dāng)分組嵌套時,我們應(yīng)該怎樣區(qū)分哪個分組是第1個分組,哪個分組是第2個分組呢? 我們通過一個小示例,即可明白,為了盡量簡化整個正則,我們直接將一些字符分組即可,示例如下。
上述正則表達(dá)式中,一共出現(xiàn)了兩個分組,一個分組嵌套著另一個分組。
可以從上圖中看出,紅色標(biāo)注的符號是一對分組符號,藍(lán)色標(biāo)注的符號是一對分組符號,紅色分組嵌套這藍(lán)色分組。 雖然上例中沒有使用到"后向引用",但是,當(dāng)我們需要使用"后向引用"時,這兩個分組哪個才是第1個分組,哪個是第2個分組呢? 當(dāng)我們需要使用后向引用時,紅色分組為第1個分組,藍(lán)色分組為第2個分組。 換句話說就是,當(dāng)使用后向引用時,"\1"引用的是紅色分組所匹配的結(jié)果,"\2"引用的是藍(lán)色分組所匹配的結(jié)果。 為什么呢?原因就是,分組的順序取決于分組符號的左側(cè)部分的順序,如下圖所示
由于紅色分組的左側(cè)部分排在最前面,所以紅色分組是整個正則中的第1個分組。 由于藍(lán)色分組的左側(cè)部分排在第2位,所以藍(lán)色分組是整個正則中的第2個分組。 注意:排序時也僅僅按照分組符號的左側(cè)部分排序,分組符號的右側(cè)部分不算在排序范圍內(nèi)。
好了,"分組"與"后向引用"就總結(jié)到這里,我想我應(yīng)該說明白了,描述起來好費(fèi)力~~~希望能夠幫到你。 之前說過,在Linux中,正則表達(dá)式分為基礎(chǔ)正則表達(dá)式與擴(kuò)展正則表達(dá)式。 而我們之前所描述的符號都屬于基本正則表達(dá)式。 在以后的文章中,我們會接觸到擴(kuò)展正則表達(dá)式,但是不用害怕,它們的用法都是相似的,而且寫法也差不多,學(xué)會基本正則表達(dá)式以后,再學(xué)習(xí)擴(kuò)展正則表達(dá)式,幾乎不會費(fèi)力。
小結(jié)為了方便以后回顧,我們將今天了解到的只是進(jìn)行總結(jié)。
\( \) 表示分組,我們可以將其中的內(nèi)容當(dāng)做一個整體,分組可以嵌套。 \(ab\) 表示將ab當(dāng)做一個整體去處理。 \1 表示引用整個表達(dá)式中第1個分組中的正則匹配到的結(jié)果。 \2 表示引用整個表達(dá)式中第2個分組中的正則匹配到的結(jié)果。 |
|