說(shuō)明:部分內(nèi)容有待進(jìn)一步研究和修正,因?yàn)樽罱ぷ魈Γ瑫簳r(shí)抽不出時(shí)間來(lái),未研究過(guò)的可以跳過(guò)這一篇,想研究的不要被我的思路所左右了,有研究清楚的還請(qǐng)指正1 問(wèn)題引出
前幾天在CSDN論壇遇到這樣一個(gè)問(wèn)題:
var str="8912341253789";
需要將這個(gè)字符串中的重復(fù)的數(shù)字給去掉,也就是結(jié)果89123457。
首先需要說(shuō)明的是,這種需求并不適合用正則來(lái)實(shí)現(xiàn),至少,正則不是最好的實(shí)現(xiàn)方式。
這個(gè)問(wèn)題本身不是本文討論的重點(diǎn),本文所要討論的,主要是由這一問(wèn)題的解決方案而引出的另一個(gè)正則匹配原理問(wèn)題。
先看一下針對(duì)這一問(wèn)題本身給出的解決方案。
復(fù)制代碼 代碼如下:
string str = "8912341253789";
Regex reg = new Regex(@"((\d)\d*?)\2");
while (str != (str = reg.Replace(str, "$1"))) { }
richTextBox2.Text = str;
/*--------輸出--------
89123457
*/
基于此有朋友提出另一個(gè)疑問(wèn),為什么使用下面的正則沒(méi)有效果
“(?=(?value>\d).*?)\kvalue>”
由此也引出本文所要討論的逆序環(huán)視更深入的一些細(xì)節(jié),涉及到逆序環(huán)視的匹配原理和匹配過(guò)程。前面的兩篇博客中雖然也有介紹,但還不夠深入,參考 正則基礎(chǔ)之——環(huán)視 和 正則應(yīng)用之——逆序環(huán)視探索 。本文將以逆序環(huán)視和反向引用結(jié)合這種復(fù)雜應(yīng)用場(chǎng)景,對(duì)逆序環(huán)視進(jìn)行深入探討。
先把問(wèn)題簡(jiǎn)化和抽象一下,上面的正則中用到了命名捕獲組和命名捕捉組的反向引用,這在一定程度上增加了問(wèn)題的復(fù)雜度,寫(xiě)成普通捕獲組,并且用“\d”代替范圍過(guò)大的“.”,如下
“(?=(\d)\d*?)\1”
需要匹配的字符串,抽象一下,取兩種典型字符串如下。
源字符串一:878
源字符串二:9878
與上面正則表達(dá)式類(lèi)似,正則表達(dá)式相應(yīng)的也有四種形式
正則表達(dá)式一:(?=(\d)\d*)\1
正則表達(dá)式二:(?=(\d)\d*?)\1
正則表達(dá)式三:(?=(\d))\d*\1
正則表達(dá)式四:(?=(\d))\d*?\1
先看一下匹配結(jié)果:
復(fù)制代碼 代碼如下:
string[] source = new string[] {"878", "9878" };
ListRegex> regs = new ListRegex>();
regs.Add(new Regex(@"(?=(\d)\d*)\1"));
regs.Add(new Regex(@"(?=(\d)\d*?)\1"));
regs.Add(new Regex(@"(?=(\d))\d*\1"));
regs.Add(new Regex(@"(?=(\d))\d*?\1"));
foreach (string s in source)
{
foreach (Regex r in regs)
{
richTextBox2.Text += "源字符串: " + s.PadRight(8, ' ');
richTextBox2.Text += "正則表達(dá)式: " + r.ToString().PadRight(18, ' ');
richTextBox2.Text += "匹配結(jié)果: " + r.Match(s).Value + "\n------------------------\n";
}
richTextBox2.Text += "------------------------\n";
}
/*--------輸出--------
源字符串: 878 正則表達(dá)式: (?=(\d)\d*)\1 匹配結(jié)果: 8
------------------------
源字符串: 878 正則表達(dá)式: (?=(\d)\d*?)\1 匹配結(jié)果:
------------------------
源字符串: 878 正則表達(dá)式: (?=(\d))\d*\1 匹配結(jié)果: 78
------------------------
源字符串: 878 正則表達(dá)式: (?=(\d))\d*?\1 匹配結(jié)果: 78
------------------------
------------------------
源字符串: 9878 正則表達(dá)式: (?=(\d)\d*)\1 匹配結(jié)果:
------------------------
源字符串: 9878 正則表達(dá)式: (?=(\d)\d*?)\1 匹配結(jié)果:
------------------------
源字符串: 9878 正則表達(dá)式: (?=(\d))\d*\1 匹配結(jié)果: 78
------------------------
源字符串: 9878 正則表達(dá)式: (?=(\d))\d*?\1 匹配結(jié)果: 78
------------------------
------------------------
*/
這個(gè)結(jié)果也許會(huì)出乎很多人的意料之外,剛開(kāi)始接觸這個(gè)問(wèn)題時(shí),我也一樣感到迷惑,放了兩天后,才靈機(jī)一觸,想通了問(wèn)題的關(guān)鍵所在,下面將展開(kāi)討論。
在此之前,可能還需要做兩點(diǎn)說(shuō)明:
1、 下面討論的話題已經(jīng)與本文開(kāi)始提到的問(wèn)題沒(méi)有多大關(guān)聯(lián)了,最初的問(wèn)題主要是為了引出本文的話題,問(wèn)題本身不在討論范圍之內(nèi),而本文也主要是純理論的探討。
2、 本文適合有一定正則基礎(chǔ)的讀者。如果您對(duì)上面幾個(gè)正則的匹配結(jié)果和匹配過(guò)程感到費(fèi)解,沒(méi)關(guān)系,下面就將為您解惑;但是如果您對(duì)上面幾個(gè)正則中元字符和語(yǔ)法代表的意義都不清楚的話,還是先從基礎(chǔ)看起吧。
2 逆序環(huán)視匹配原理深入
正則表達(dá)式一:(?=(\d)\d*)\1
正則表達(dá)式二:(?=(\d)\d*?)\1
正則表達(dá)式三:(?=(\d))\d*\1
正則表達(dá)式四:(?=(\d))\d*?\1
上面的幾個(gè)正則表達(dá)式,可以最終抽象為“(?=SubExp1)SubExp2”這樣的表達(dá)式,在做逆序環(huán)視原理分析時(shí),根據(jù)“SubExp1”的特點(diǎn),可以歸納為三類(lèi):
1、 逆序環(huán)視中的子表達(dá)式“SubExp1”長(zhǎng)度固定,正則表達(dá)式三和四屬于這一類(lèi),當(dāng)然,這一類(lèi)里是包括“?”這一量詞的,但也僅限于這一個(gè)量詞。
2、 逆序環(huán)視中的子表達(dá)式“SubExp1”長(zhǎng)度不固定,其中包含忽略優(yōu)先量詞,如“*?”、“+?”、“{m,}?”等,也就是通常所說(shuō)的非貪婪模式,正則表達(dá)式二屬于這一類(lèi)。
3、 逆序環(huán)視中的子表達(dá)式“SubExp1”長(zhǎng)度不固定,其中包含匹配優(yōu)先量詞,“*”、“+”、“{m,}”等,也就是通常所說(shuō)的貪婪模式,正則表達(dá)式一屬于這一類(lèi)。
下面針對(duì)這三類(lèi)正則表達(dá)式進(jìn)行匹配過(guò)程的分析。
2.1 固定長(zhǎng)度子表達(dá)式匹配過(guò)程分析
2.1.1 源字符串一 + 正則表達(dá)式三匹配過(guò)程
源字符串一:878
正則表達(dá)式三:(?=(\d))\d*\1
首先在位置0處開(kāi)始嘗試匹配,由“(?=(\d))”取得控制權(quán),長(zhǎng)度固定,只有一位,由位置0處向左查找一位,失敗,“(?=(\d))”匹配失敗,導(dǎo)致第一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置1處嘗試匹配,控制權(quán)交給“(?=(\d))”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”?!癨d”取得控制權(quán)后,向右嘗試匹配,匹配“8”成功,此時(shí)“(?=(\d))”匹配成功,匹配結(jié)果為位置1,捕獲組1匹配到的內(nèi)容就是“8”,控制權(quán)交給“\d*”。由于“\d*”為貪婪模式,會(huì)優(yōu)先嘗試匹配位置1后面的“7”和“8”,匹配成功,記錄回溯狀態(tài),控制權(quán)交給“\1”。由于前面捕獲組1捕獲到的內(nèi)容是“8”,所以“\1”要匹配到“8”才能匹配成功,而此時(shí)已到達(dá)字符串結(jié)尾處,匹配失敗,“\d*”回溯,讓出最后的字符“8”,再將控制權(quán)交給“\1”, 由“\1”匹配最后的“8”成功,此時(shí)整個(gè)表達(dá)式匹配成功。由于“(?=(\d))”只匹配位置,不占有字符,所以整個(gè)表達(dá)式匹配到的結(jié)果為“78”,其中“\d*”匹配到的是“7”,“\1”匹配到的是“8”。
2.1.2 源字符串二 + 正則表達(dá)式三匹配過(guò)程
源字符串二:9878
正則表達(dá)式三:(?=(\d))\d*\1
這一組合的匹配過(guò)程,與2.1.1節(jié)的匹配過(guò)程基本類(lèi)似,只不過(guò)多了一輪匹配嘗試而已,這里不再贅述。
2.1.3 源字符串一 + 正則表達(dá)式四匹配過(guò)程
源字符串一:878
正則表達(dá)式四:(?=(\d))\d*?\1
首先在位置0處開(kāi)始嘗試匹配,由“(?=(\d))”取得控制權(quán),長(zhǎng)度固定,只有一位,由位置0處向左查找一位,失敗,“(?=(\d))”匹配失敗,導(dǎo)致第一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置1處嘗試匹配,控制權(quán)交給“(?=(\d))”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”。“\d”取得控制權(quán)后,向右嘗試匹配,匹配“8”成功,此時(shí)“(?=(\d))”匹配成功,匹配結(jié)是果為位置1,捕獲組1匹配到的內(nèi)容就是“8”,控制權(quán)交給“\d*?”。由于“\d*?”為非貪婪模式,會(huì)優(yōu)先嘗試忽略匹配,記錄回溯狀態(tài),控制權(quán)交給“\1”。由于前面捕獲組1捕獲到的內(nèi)容是“8”,所以“\1”要匹配到“8”才能匹配成功,而此時(shí)位置1后面的字符是“7”,匹配失敗,“\d*?”回溯,嘗試匹配位置1后面的字符“7”,再將控制權(quán)交給“\1”, 由“\1”匹配最后的“8”成功,此時(shí)整個(gè)表達(dá)式匹配成功。由于“(?=(\d))”只匹配位置,不占有字符,所以整個(gè)表達(dá)式匹配到的結(jié)果為“78”,其中“\d*?”匹配到的是“7”,“\1”匹配到的是最后的“8”。
這與2.1.1節(jié)組合的匹配過(guò)程基本一致,只不過(guò)就是“\d*”和“\d*?”匹配與回溯過(guò)程有所區(qū)別而已。
2.1.4 源字符串二 + 正則表達(dá)式四匹配過(guò)程
源字符串二:9878
正則表達(dá)式四:(?=(\d))\d*?\1
這一組合的匹配過(guò)程,與2.1.3節(jié)的匹配過(guò)程基本類(lèi)似,這里不再贅述。
2.2 非貪婪模式子表達(dá)式匹配過(guò)程分析
2.2.1 源字符串一 + 正則表達(dá)式二匹配過(guò)程
源字符串一:878
正則表達(dá)式二:(?=(\d)\d*?)\1
首先在位置0處開(kāi)始嘗試匹配,由“(?=(\d)\d*?)”取得控制權(quán),長(zhǎng)度不固定,至少一位,由位置0處向左查找一位,失敗,“(?=(\d)\d*?)”匹配失敗,導(dǎo)致第一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置1處嘗試匹配,控制權(quán)交給“(?=(\d)\d*?)”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”。“\d”取得控制權(quán)后,向右嘗試匹配,匹配“8”成功,將控制權(quán)交給“\d*?”,由于“\d*?”為非貪婪模式,會(huì)優(yōu)先嘗試忽略匹配,即不匹配任何內(nèi)容,并記錄回溯狀態(tài),此時(shí)“(\d)\d*?”匹配成功,那么“(?=(\d)\d*?)”也就匹配成功,匹配結(jié)果為位置1,由于此處的子表達(dá)式“(\d)\d*?”為非貪婪模式,取得一個(gè)成功匹配項(xiàng)后,即交出控制權(quán),同時(shí)丟棄所有回溯狀態(tài)。由于前面捕獲組1捕獲到的內(nèi)容是“8”,所以“\1”要匹配到“8”才能匹配成功,而此時(shí)位置1后面的字符是“7”,此時(shí)已無(wú)可供回溯的狀態(tài),整個(gè)表達(dá)式在位置1處匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置2處嘗試匹配,控制權(quán)交給“(?=(\d)\d*?)”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”?!癨d”取得控制權(quán)后,向右嘗試匹配,匹配“7”成功,將控制權(quán)交給“\d*?”,由于“\d*?”為非貪婪模式,會(huì)優(yōu)先嘗試忽略匹配,即不匹配任何內(nèi)容,并記錄回溯狀態(tài),此時(shí)“(\d)\d*?”匹配成功,那么“(?=(\d)\d*?)”也就匹配成功,匹配結(jié)果為位置2,由于此處的子表達(dá)式“(\d)\d*?”為非貪婪模式,取得一個(gè)成功匹配項(xiàng)后,即交出控制權(quán),同時(shí)丟棄所有回溯狀態(tài)。由于前面捕獲組1捕獲到的內(nèi)容是“7”,所以“\1”要匹配到“7”才能匹配成功,而此時(shí)位置2后面的字符是“7”,此時(shí)已無(wú)可供回溯的狀態(tài),整個(gè)表達(dá)式在位置2處匹配失敗。
位置3處的匹配過(guò)程也同樣道理,最后“\1”因無(wú)字符可匹配,導(dǎo)致整個(gè)表達(dá)式匹配失敗。
此時(shí)已嘗試了字符串所有位置,均匹配失敗,所以整個(gè)表達(dá)式匹配失敗,未取得任何有效匹配結(jié)果。
2.2.2 源字符串二 + 正則表達(dá)式二匹配過(guò)程
源字符串一:9878
正則表達(dá)式二:(?=(\d)\d*?)\1
這一組合的匹配過(guò)程,與2.2.1節(jié)的匹配過(guò)程基本類(lèi)似,這里不再贅述。
2.3 貪婪模式子表達(dá)式匹配過(guò)程分析
2.3.1 源字符串一 + 正則表達(dá)式一匹配過(guò)程
源字符串一:878
正則表達(dá)式二:(?=(\d)\d*)\1
首先在位置0處開(kāi)始嘗試匹配,由“(?=(\d)\d*)”取得控制權(quán),長(zhǎng)度不固定,至少一位,由位置0處向左查找一位,失敗,“(?=(\d)\d*)”匹配失敗,導(dǎo)致第一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置1處嘗試匹配,控制權(quán)交給“(?=(\d)\d*)”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”?!癨d”取得控制權(quán)后,向右嘗試匹配,匹配“8”成功,將控制權(quán)交給“\d*”,由于“\d*”為貪婪模式,會(huì)優(yōu)先嘗試匹配,并記錄回溯狀態(tài),但此時(shí)已沒(méi)有可用于匹配的字符,所以匹配失敗,回溯,不匹配任何內(nèi)容,丟棄回溯狀態(tài),此時(shí)“(\d)\d*”匹配成功,匹配內(nèi)容為“8”,那么“(?=(\d)\d*)”也就匹配成功,匹配結(jié)果是位置1,由于此處的子表達(dá)式為貪婪模式,“(\d)\d*”取得一個(gè)成功匹配項(xiàng)后,需要查找是否還有更長(zhǎng)匹配,找到最長(zhǎng)匹配后,才會(huì)交出控制權(quán)。再向左查找,已沒(méi)有字符,“8”已是最長(zhǎng)匹配,此時(shí)交出控制權(quán),同時(shí)丟棄所有回溯狀態(tài)。由于前面捕獲組1捕獲到的內(nèi)容是“8”,所以“\1”要匹配到“8”才能匹配成功,而此時(shí)位置1后面的字符是“7”,此時(shí)已無(wú)可供回溯的狀態(tài),整個(gè)表達(dá)式在位置1處匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置2處嘗試匹配,控制權(quán)交給“(?=(\d)\d*)”,向左查找一位,接著將控制權(quán)交給“(\d)”,更進(jìn)一步的將控制權(quán)交給“\d”?!癨d”取得控制權(quán)后,向右嘗試匹配,匹配“7”成功,將控制權(quán)交給“\d*”,由于“\d*”為貪婪模式,會(huì)優(yōu)先嘗試匹配,并記錄回溯狀態(tài),但此時(shí)已沒(méi)有可用于匹配的字符,所以匹配失敗,回溯,不匹配任何內(nèi)容,丟棄回溯狀態(tài),此時(shí)“(\d)\d*”匹配成功,匹配內(nèi)容為“7”,那么“(?=(\d)\d*)”也就匹配成功,匹配結(jié)果是位置2,由于此處的子表達(dá)式為貪婪模式,“(\d)\d*”取得一個(gè)成功匹配項(xiàng)后,需要查找是否還有更長(zhǎng)匹配,找到最長(zhǎng)匹配后,才會(huì)交出控制權(quán)。再向左查找,由位置0處向右嘗試匹配,“\d”取得控制權(quán)后,匹配位置0處的“8”成功,將控制權(quán)交給“\d*”,由于“\d*”為貪婪模式,會(huì)優(yōu)先嘗試匹配,并記錄回溯狀態(tài),匹配位置1處的“7”成功,此時(shí)“(\d)\d*”匹配成功,那么“(\d)\d*”又找到了一個(gè)成功匹配項(xiàng),匹配內(nèi)容為“87”,其中捕獲組1匹配到的是“8”。再向左查找,已沒(méi)有字符,“87”已是最長(zhǎng)匹配,此時(shí)交出控制權(quán),同時(shí)丟棄所有回溯狀態(tài)。由于前面捕獲組1捕獲到的內(nèi)容是“8”,所以“\1”匹配位置2處的“8”匹配成功,此時(shí)整個(gè)有達(dá)式匹配成功。
演示例程中用的是Match,只取一次匹配項(xiàng),事實(shí)上如果用的是Matches,正則表達(dá)式是需要嘗試所有位置的,對(duì)于這一組合,同樣道理,在位置3處,由于“\1”沒(méi)有字符可供匹配,所以匹配一定是失敗的。
至此,這一組合的匹配完成,有一個(gè)成功匹配項(xiàng),匹配結(jié)果為“8”,匹配開(kāi)始位置為位置2,也就是匹配到的內(nèi)容為第二個(gè)“8”。
2.3.2 源字符串二 + 正則表達(dá)式一匹配過(guò)程
源字符串二:9878
正則表達(dá)式二:(?=(\d)\d*)\1
首先在位置0處開(kāi)始嘗試匹配,由“(?=(\d)\d*)”取得控制權(quán),長(zhǎng)度不固定,至少一位,由位置0處向左查找一位,失敗,“(?=(\d)\d*)”匹配失敗,導(dǎo)致第一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置1處嘗試匹配,這一輪的匹配過(guò)程與2.3.1節(jié)的組合在位置1處的匹配過(guò)程類(lèi)似,只不過(guò)“(\d)\d*”匹配到的是“9”,捕獲組1匹配到的也是“9”,因此“\1”匹配失敗,導(dǎo)致整個(gè)表達(dá)式在位置1處匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置2處嘗試匹配,這一輪的匹配過(guò)程與2.3.1節(jié)的組合在位置2處的匹配過(guò)程類(lèi)似。首先“(\d)\d*”找到一個(gè)成功匹配項(xiàng),匹配到的內(nèi)容是“8”,捕捉組1匹配到的內(nèi)容也是“8”,此時(shí)再向左嘗試匹配,又找到一個(gè)成功匹配項(xiàng),匹配到的內(nèi)容是“98”,捕捉組1匹配到的內(nèi)容也是“9”,再向左查找時(shí),已無(wú)字符,所以“98”就是最長(zhǎng)匹配項(xiàng),“(?=(\d)\d*)”匹配成功,匹配結(jié)果是位置2。由于此時(shí)捕獲組1匹配的內(nèi)容是“9”,所以“\1”在位置2處匹配失敗,導(dǎo)致整個(gè)表達(dá)式在位置2處匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向前傳動(dòng),由位置3處嘗試匹配,這一輪的匹配過(guò)程與上一輪在位置2處的匹配過(guò)程類(lèi)似。首先“(\d)\d*”找到一個(gè)成功匹配項(xiàng)“7”,繼續(xù)向左嘗試,又找到一個(gè)成功匹配項(xiàng)“87”,再向左嘗試,又找到一個(gè)成功匹配項(xiàng)“987”,此時(shí)已為最長(zhǎng)匹配,交出控制權(quán),并丟棄所有回溯狀態(tài)。此時(shí)捕獲組1匹配的內(nèi)容是“9” 所以“\1”在位置3處匹配失敗,導(dǎo)致整個(gè)表達(dá)式在位置3處匹配失敗。
位置4處最終由于“\1”沒(méi)有字符可供匹配,所以匹配一定是失敗的。
至此在源字符串所有位置的匹配嘗試都已完成,整個(gè)表達(dá)式匹配失敗,未找到成功匹配項(xiàng)。
2.4 小結(jié)
以上匹配過(guò)程分析,看似繁復(fù),其實(shí)把握以下幾點(diǎn)就可以了。
1、 逆序環(huán)視中子表達(dá)式為固定長(zhǎng)度時(shí),要么匹配成功,要么匹配失敗,沒(méi)什么好說(shuō)的。
2、 逆序環(huán)視中子表達(dá)式為非貪婪模式時(shí),只要找到一個(gè)匹配成功項(xiàng),即交出控制權(quán),并丟棄所有可供回溯的狀態(tài)。
3、 逆序環(huán)視中子表達(dá)式為貪婪模式時(shí),只有找到最長(zhǎng)匹配成功項(xiàng)時(shí),才會(huì)即交出控制權(quán),并丟棄所有可供回溯的狀態(tài)。
也就是說(shuō),對(duì)于正則表達(dá)式“(?=SubExp1)SubExp2”,一旦“(?=SubExp1)”交出控制權(quán),那么它所匹配的位置就已固定,“SubExp1”所匹配的內(nèi)容也已固定,并且沒(méi)有可供回溯的狀態(tài)了。
3 逆序環(huán)視匹配原理總結(jié)
再來(lái)總結(jié)一下正則表達(dá)式“(?=SubExp1)SubExp2”的匹配過(guò)程吧。逆序環(huán)視的匹配原理圖如下圖所示。
圖3-1 逆序環(huán)視匹配原理圖
正則表達(dá)式“(?=SubExp1)SubExp2”的匹配過(guò)程,可分為主匹配流程和子匹配流程兩個(gè)流程,主匹配流程如下圖所示。
圖3-2 主匹配流程圖
主匹配流程:
1、 由位置0處向右嘗試匹配,在找到滿足“(?=SubExp1)”最小長(zhǎng)度要求的位置前,匹配一定是失敗的,直到找到這樣一個(gè)的位置x,x滿足“(?=SubExp1)”最小長(zhǎng)度要求;
2、 從位置x處向左查找滿足“SubExp1”最小長(zhǎng)度要求的位置y;
3、 由“SubExp1”從位置y開(kāi)始向右嘗試匹配,此時(shí)進(jìn)入一個(gè)獨(dú)立的子匹配過(guò)程;
4、 如果“SubExp1”在位置y處子匹配還需要下一輪子匹配,則再向左查找一個(gè)y',也就是y-1重新進(jìn)入獨(dú)立的子匹配過(guò)程,如此循環(huán),直到不再需要下一輪子匹配,子匹配成功則進(jìn)入步驟5,最終匹配失敗則報(bào)告整個(gè)表達(dá)式匹配失敗;
5、 “(?=SubExp1)”成功匹配后,控制權(quán)交給后面的子表達(dá)式“SubExp2”,繼續(xù)嘗試匹配,直到整個(gè)表達(dá)式匹配成功或失敗,報(bào)告在位置x處整個(gè)表達(dá)式匹配成功或失?。?
6、 如有必要,繼續(xù)查找下一位置x',并開(kāi)始新一輪嘗試匹配。
子匹配流程如下圖所示。
圖3-3 子匹配流程圖
子匹配過(guò)程:
1、 進(jìn)入子匹配后,源字符串即已確定,也就是位置y和位置x之間的子字符串,而此時(shí)的正則表達(dá)式則變成了“^SubExp1$”,因?yàn)樵谶@一輪子匹配當(dāng)中,一旦匹配成功,則匹配開(kāi)始位置一定是y,匹配結(jié)束位置一定是x;
2、 子表達(dá)式長(zhǎng)度固定時(shí),要么匹配成功,要么匹配失敗,返回匹配結(jié)果,并且不需要下一輪子匹配;
3、 子表達(dá)式長(zhǎng)度不固定時(shí),區(qū)分是非貪婪模式還是貪婪模式;
4、 如果是非貪婪模式,匹配失敗,報(bào)告失敗,并且要求進(jìn)行下一輪子匹配;匹配成功,丟棄所有回溯狀態(tài),報(bào)告成功,并且不再需要嘗試下一輪子匹配;
5、 如果是貪婪模式,匹配失敗,報(bào)告失敗,并且要求進(jìn)行下一輪子匹配;匹配成功,丟棄所有回溯狀態(tài),報(bào)告成功,記錄本次匹配成功內(nèi)容,并且要求嘗試下一輪子匹配,直到取得最長(zhǎng)匹配為止;
在特定的一輪匹配中,x的位置是固定的,而逆序環(huán)視中的子表達(dá)式“SubExp1”,在報(bào)告最終的匹配結(jié)果前,匹配開(kāi)始的位置是不可預(yù)知的,需要經(jīng)過(guò)一輪以上的子匹配才能確定,但匹配結(jié)束的位置一定是位置x。
當(dāng)然,這只是針對(duì)特定的一輪匹配而言的,當(dāng)這輪匹配失敗,正則引擎?zhèn)鲃?dòng)裝置會(huì)向前傳動(dòng),使x=x+1,再進(jìn)入下一輪匹配嘗試,直到整個(gè)表達(dá)式報(bào)告匹配成功或失敗為止。
至此逆序環(huán)視的匹配原理已基本上分析完了,當(dāng)然,還有更復(fù)雜的,如“SubExp1”中既包含貪婪模式子表達(dá)式,又包含非貪婪模式子表達(dá)式,但無(wú)論怎樣復(fù)雜,都是要遵循以上匹配原理的,所以只要理解了以上匹配原理,逆序環(huán)視也就沒(méi)什么秘密可言了。
您可能感興趣的文章:- 正則表達(dá)式中環(huán)視的簡(jiǎn)單應(yīng)用示例【基于java】
- 正則應(yīng)用之 逆序環(huán)視探索 .
- 正則基礎(chǔ)之 環(huán)視 Lookaround
- javascript 正則表達(dá)式分組、斷言詳解
- 正則表達(dá)式之零寬斷言實(shí)例詳解【基于PHP】
- 正則表達(dá)式零寬斷言詳解
- 正則表達(dá)式斷言、巡視(Assertions)、正向斷言、反向斷言介紹
- 正則表達(dá)式環(huán)視概念與用法分析