正則應(yīng)用之 逆序環(huán)視探索 .
1、問(wèn)題引出
前幾天在CSDN論壇遇到這樣一個(gè)問(wèn)題。
我要通過(guò)正則分別取出下面 <font color="#008000"> 與 </font> 之間的字符串
1、在 <font color="#008000"> 與 </font> 之間的字符串是沒(méi)法固定的,是隨機(jī)自動(dòng)生成的
2、其中 <font color="#008000"> 與 </font>的數(shù)量也是沒(méi)法固定的,也是隨機(jī)自動(dòng)生成的
<font color="#008000"> ** 這里是不固定的字符串1 ** </font>
<font color="#008000"> ** 這里是不固定的字符串2 ** </font>
<font color="#008000"> ** 這里是不固定的字符串3 ** </font>
有朋友給出這樣的正則“(?<=<font[\s\S]*?>)([\s\S]*?)(?=</font>)”,看下匹配結(jié)果。
string test = @"<font color=""#008000""> ** 這里是不固定的字符串1 ** </font> <font color=""#008000""> ** 這里是不固定的字符串2 ** </font> <font color=""#008000""> ** 這里是不固定的字符串3 ** </font> "; MatchCollection mc = Regex.Matches(test, @"(?<=<font[\s\S]*?>)([\s\S]*?)(?=</font>)"); foreach (Match m in mc) { richTextBox2.Text += m.Value + "\n---------------\n"; } /*--------輸出-------- ** 這里是不固定的字符串1 ** --------------- <font color="#008000"> ** 這里是不固定的字符串2 ** --------------- <font color="#008000"> ** 這里是不固定的字符串3 ** --------------- */ 為什么會(huì)是這樣的結(jié)果,而不是我們期望的如下的結(jié)果呢? /*--------輸出-------- ** 這里是不固定的字符串1 ** --------------- ** 這里是不固定的字符串2 ** --------------- ** 這里是不固定的字符串3 ** --------------- */
這涉及到逆序環(huán)視的匹配原理,以及貪婪與非貪婪模式應(yīng)用的一些細(xì)節(jié),下面先針對(duì)逆序環(huán)視的匹配細(xì)節(jié)展開(kāi)討論,然后再回過(guò)頭來(lái)看下這個(gè)問(wèn)題。
2、逆序環(huán)視匹配原理
關(guān)于環(huán)視的一些基礎(chǔ)講解和基本匹配原理,在正則基礎(chǔ)之——環(huán)視這篇博客里已有所介紹,只不過(guò)當(dāng)時(shí)整理得比較匆忙,沒(méi)有涉及更詳細(xì)的匹配細(xì)節(jié)。這里僅針對(duì)逆序環(huán)視展開(kāi)討論。
逆序環(huán)視的基礎(chǔ)知識(shí)在上面博文中已介紹過(guò),這里簡(jiǎn)單引用一下。
表達(dá)式 | 說(shuō)明 |
(?<=Expression) | 逆序肯定環(huán)視,表示所在位置左側(cè)能夠匹配Expression |
(?<!Expression) | 逆序否定環(huán)視,表示所在位置左側(cè)不能匹配Expression |
對(duì)于逆序肯定環(huán)視(?<=Expression)來(lái)說(shuō),當(dāng)子表達(dá)式Expression匹配成功時(shí),(?<=Expression)匹配成功,并報(bào)告(?<=Expression)匹配當(dāng)前位置成功。
對(duì)于逆序否定環(huán)視(?<!Expression)來(lái)說(shuō),當(dāng)子表達(dá)式Expression匹配成功時(shí),(?<!Expression)匹配失敗;當(dāng)子表達(dá)式Expression匹配失敗時(shí),(?<!Expression)匹配成功,并報(bào)告(?<!Expression)匹配當(dāng)前位置成功。
2.1 逆序環(huán)視匹配行為分析
2.1.1 逆序環(huán)視支持現(xiàn)狀
目前支持逆序環(huán)視的語(yǔ)言還比較少,比如當(dāng)前比較流行的腳本語(yǔ)言JavaScript中就是不支持逆序環(huán)視的。個(gè)人認(rèn)為不支持逆序環(huán)視已成為目前JavaScript中使用正則的最大限制,一些使用逆序環(huán)視很輕松搞定的輸入驗(yàn)證,卻要通過(guò)各種變通的方式來(lái)實(shí)現(xiàn)。
需求:驗(yàn)證輸入由字母、數(shù)字和下劃線(xiàn)組成,下劃線(xiàn)不能出現(xiàn)在開(kāi)始或結(jié)束位置。
對(duì)于這樣的需求,如果支持逆序環(huán)視,直接“^(?!_)[a-zA-Z0-9_]+(?<!_)$”就可以了搞定了,但是在JavaScript中,卻需要用類(lèi)似于“^[a-zA-Z0-9]([a-zA-Z0-9_]*[a-zA-Z0-9])?$”這種變通方式來(lái)實(shí)現(xiàn)。這只是一個(gè)簡(jiǎn)單的例子,實(shí)際的應(yīng)用中,會(huì)比這復(fù)雜得多,而為了避免量詞的嵌套帶來(lái)的效率陷阱,正則實(shí)現(xiàn)起來(lái)很困難,甚至有些情況不得不拆分成多個(gè)正則來(lái)實(shí)現(xiàn)。
而另一些流行的語(yǔ)言,比如Java中,雖然支持逆序環(huán)視,但只支持固定長(zhǎng)度的子表達(dá)式,量詞也只支持“?”,其它不定長(zhǎng)度的量詞如“*”、“+” 、“{m,n}”等是不支持的。
源字符串:<div>a test</div>
需求:取得div標(biāo)簽的內(nèi)容,不包括div標(biāo)簽本身
Java代碼實(shí)現(xiàn):
import java.util.regex.*; String test = "<div>a test</div>"; String reg = "(?<=<div>)[^<]+(?=</div>)"; Matcher m = Pattern.compile(reg).matcher(test); while(m.find()) { System.out.println(m.group()); } /*--------輸出-------- a test */
但是如果源字符串變一下,加個(gè)屬性變成“<div id=”test1”>a test</div>”,那么除非標(biāo)簽中屬性?xún)?nèi)容是固定的,否則就無(wú)法在Java中用逆序環(huán)視來(lái)實(shí)現(xiàn)了。
為什么在很多流行語(yǔ)言中,要么不支持逆序環(huán)視,要么只支持固定長(zhǎng)度的子表式呢?先來(lái)分析一下逆序環(huán)視的匹配原理吧。
2.1.2 Java中逆序環(huán)視匹配原理分析
不支持逆序環(huán)視的自不必說(shuō),只支持固定長(zhǎng)度子表達(dá)式的逆序環(huán)視如何呢。
源字符串:<div>a test</div>
正則表達(dá)式:(?<=<div>)[^<]+(?=</div>)
需要明確的一點(diǎn),無(wú)論是什么樣的正則表達(dá)式,都是要從字符串的位置0處開(kāi)始嘗試匹配的。
首先由“(?<=<div>)”取得控制權(quán),由位置0開(kāi)始嘗匹配,由于“<div>”的長(zhǎng)度固定為5,所以會(huì)從當(dāng)前位置向左查找5個(gè)字符,但是由于此時(shí)位于位置0處,前面沒(méi)有任何字符,所以嘗試匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向右傳動(dòng),由位置1處開(kāi)始嘗試匹配,同樣匹配失敗,直到位置5處,向左查找5個(gè)字符,滿(mǎn)足條件,此時(shí)把控制權(quán)交給“(?<=<div>)”中的子表達(dá)式“<div>”。“<div>”取得控制權(quán)后,由位置0處開(kāi)始向右嘗試匹配,由于正則都是逐字符進(jìn)行匹配的,所以這時(shí)會(huì)把控制權(quán)交給“<div>”中的“<”,由“<”嘗試字符串中的“<”,匹配成功,接下來(lái)由“d”嘗試字符串中的“d”,匹配成功,同樣的過(guò)程,由“<div>”匹配位置0到位置5之間的“<div>”成功,此時(shí)“(?<=<div>)”匹配成功,匹配成功的位置是位置5。
后續(xù)的匹配過(guò)程請(qǐng)參考 正則基礎(chǔ)之——環(huán)視 和 正則基礎(chǔ)之——NFA引擎匹配原理。
那么對(duì)于量詞“?”又是怎么樣一種情況呢,看一下下面的例子。
源字符串:cba
正則表達(dá)式:(?<=(c?b))a
String test = "cba"; String reg = "(?<=(c?b))a"; Matcher m = Pattern.compile(reg).matcher(test); while(m.find()) { System.out.println(m.group()); System.out.println(m.group(1)); } /*--------輸出-------- a b */
可以看到,“c?”并沒(méi)有參與匹配,在這里,“?”并不具備貪婪模式的作用,“?”只提供了一個(gè)分支的作用,共記錄了兩個(gè)分支,一個(gè)分支需要從當(dāng)前位置向前查找一個(gè)字符,另一個(gè)分支需要從當(dāng)前位置向前查找兩個(gè)字符。正則引擎從當(dāng)前位置,嘗試這兩種情況,優(yōu)先嘗試的是需要向前查找較少字符的分支,匹配成功,則不再?lài)L試另一個(gè)分支,只有這一分支匹配失敗時(shí),才會(huì)去嘗試另一個(gè)分支。
String test = "dcba"; String reg = "(?<=(dc?b))a"; Matcher m = Pattern.compile(reg).matcher(test); while(m.find()) { System.out.println(m.group()); System.out.println(m.group(1)); } /*--------輸出-------- a dcb */
雖然有兩個(gè)分支,但向前查找的字符數(shù)可預(yù)知的,所以只支持“?”時(shí)并不復(fù)雜,但如果再支持其它不定長(zhǎng)度量詞,情況又如何呢?
2.1.3 .NET中逆序環(huán)視匹配原理
.NET的逆序環(huán)視中,是支持不定長(zhǎng)度量詞的,在這個(gè)時(shí)候,匹配過(guò)程就變得復(fù)雜了。先看一下定長(zhǎng)的是如何匹配的。
string test = "<div>a test</div>"; Regex reg = new Regex(@"(?<=<div>)[^<]+(?=</div>)"); Match m = reg.Match(test); if (m.Success) { richTextBox2.Text += m.Value + "\n"; } /*--------輸出-------- a test */
從結(jié)果可以看到,.NET中的逆序環(huán)視在子表達(dá)式長(zhǎng)度固定時(shí),匹配行為與Java中應(yīng)該是一樣的。那么不定長(zhǎng)量詞又如何呢?
string test = "cba"; Regex reg = new Regex(@"(?<=(c?b))a"); Match m = reg.Match(test); if (m.Success) { richTextBox2.Text += m.Value + "\n"; richTextBox2.Text += m.Groups[1].Value + "\n"; } /*--------輸出-------- a cb */
可以看到,這里的“?”具備了貪婪模式的特性。那么這個(gè)時(shí)候是否會(huì)有這樣的疑問(wèn),它的匹配過(guò)程仍然是從當(dāng)前位置向左嘗試,還是從字符串開(kāi)始位置向右嘗試匹配呢?
string test = "<ddd<cccba"; Regex reg = new Regex(@"(?<=(<.*?b))a"); Match m = reg.Match(test); if (m.Success) { richTextBox2.Text += m.Value + "\n"; richTextBox2.Text += m.Groups[1].Value + "\n"; } /*--------輸出-------- a <cccb */
從結(jié)果可看出,在逆序環(huán)視中有不定量詞的時(shí)候,仍然是從當(dāng)前位置,向左嘗試匹配的,否則Groups[1]的內(nèi)容就是“<ddd<cccb”,而不是“<cccb”了。
這是非貪婪模式的匹配情況,再看一下貪婪模式匹配的情況。
string test = "e<ddd<cccba"; Regex reg = new Regex(@"(?<=(<.*b))a"); Match m = reg.Match(test); if (m.Success) { richTextBox2.Text += m.Value + "\n"; richTextBox2.Text += m.Groups[1].Value + "\n"; } /*--------輸出-------- a <ddd<cccb */
可以看到,采用貪婪模式以后,雖然嘗試到“c”前面的“<”時(shí)已經(jīng)可以匹配成功,但由于是貪婪模式,還是要繼續(xù)嘗試匹配的。直到嘗試到開(kāi)始位置,取最長(zhǎng)的成功匹配作為匹配結(jié)果。
2.2 匹配過(guò)程
再來(lái)理一下逆序環(huán)視的匹配過(guò)程吧。
源字符串:<div id=“test1”>a test</div>
正則表達(dá)式:(?<=<div[^>]*>)[^<]+(?=</div>)
首先由“(?<=<div[^>]*>)”取得控制權(quán),由位置0開(kāi)始嘗匹配,由于“<div[^>]*>”的長(zhǎng)度不固定,所以會(huì)從當(dāng)前位置向左逐字符查找,當(dāng)然,也有可能正則引擎做了優(yōu)化,先計(jì)算一下最小長(zhǎng)度后向前查找,在這里“<div[^>]*>”至少需要5個(gè)字符,所以由當(dāng)前位置向左查找5個(gè)字符,才開(kāi)始嘗試匹配,這要看各語(yǔ)言的正則引擎如何實(shí)現(xiàn)了,我推測(cè)是先計(jì)算最小長(zhǎng)度。但是由于此時(shí)位于位置0處,前面沒(méi)有任何字符,所以嘗試匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向右傳動(dòng),由位置1處開(kāi)始嘗試匹配,同樣匹配失敗,直到位置5處,向左查找5個(gè)字符,滿(mǎn)足條件,此時(shí)把控制權(quán)交給“(?<=<div[^>]*>)”中的子表達(dá)式“<div[^>]*>”。“<div[^>]*>”取得控制權(quán)后,由位置0處開(kāi)始向右嘗試匹配,由于正則都是逐字符進(jìn)行匹配的,所以這時(shí)會(huì)把控制權(quán)交給“<div[^>]*>”中的“<”,由“<”嘗試字符串中的“<”,匹配成功,接下來(lái)由“d”嘗試字符串中的“d”,匹配成功,同樣的過(guò)程,由“<div[^>]*”匹配位置0到位置5之間的“<div ”成功,其中“[^>]*”在匹配“<div ”中的空格時(shí)是要記錄可供回溯的狀態(tài)的,此時(shí)控制權(quán)交給“>”,由于已沒(méi)有任何字符可供匹配,所以“>”匹配失敗,此時(shí)進(jìn)行回溯,由“[^>]*”讓出已匹配的空格給“>”進(jìn)行匹配,同樣匹配失敗,此時(shí)已沒(méi)有可供回溯的狀態(tài),所以這一輪匹配嘗試失敗。
正則引擎?zhèn)鲃?dòng)裝置向右傳動(dòng),由位置6處開(kāi)始嘗試匹配,同樣匹配失敗,直到位置16處,此時(shí)的當(dāng)前位置指的就是位置16,把控制權(quán)交給“(?<=<div[^>]*>)”,向左查找5個(gè)字符,滿(mǎn)足條件,記錄回溯狀態(tài),控制權(quán)交給“(?<=<div[^>]*>)”中的子表達(dá)式“<div[^>]*>”。“<div[^>]*>”取得控制權(quán)后,由位置11處開(kāi)始向右嘗試匹配, “<div[^>]*>”中的“<”嘗試字符串中的“s”,匹配失敗。繼續(xù)向左嘗試,在位置10處由“<”嘗試字符串中的“e”,匹配失敗。同樣的過(guò)程,直到嘗試到位置0處,由“<div[^>]*”在位置0向右嘗試匹配,成功匹配到“<div id=“test1”>”,此時(shí)“(?<=<div[^>]*>)”匹配成功,控制權(quán)交給“[^>]+”,繼續(xù)進(jìn)行下面的匹配,直到整個(gè)表達(dá)式匹配成功。
總結(jié)正則表達(dá)式“(?<=SubExp1) SubExp2”的匹配過(guò)程:
1、 由位置0處向右嘗試匹配,直到找到一個(gè)滿(mǎn)足“(?<=SubExp1) ”最小長(zhǎng)度要求的位置x;
2、 從位置x處向左查找滿(mǎn)足“SubExp1”最小長(zhǎng)度要求的位置y;
3、 由“SubExp1”從位置y開(kāi)始向右嘗試匹配;
4、 如果“SubExp1”為固定長(zhǎng)度或非貪婪模式,則找到一個(gè)成功匹配項(xiàng)即停止嘗試匹配;
5、 如果“SubExp1”為貪婪模式,則要嘗試所有的可能,取最長(zhǎng)的成功匹配項(xiàng)作為匹配結(jié)果。
6、 “(?<=SubExp1) ”成功匹配后,控制權(quán)交給后面的子表達(dá)式,繼續(xù)嘗試匹配。
需要說(shuō)明的一點(diǎn),逆序環(huán)視中的子表達(dá)式“SubExp1”,匹配成功時(shí),匹配開(kāi)始的位置是不可預(yù)知的,但匹配結(jié)束的位置一定是位置x。
3、問(wèn)題分析與總結(jié)
3.1 問(wèn)題分析
那么再回過(guò)頭來(lái)看下最初的問(wèn)題。
string test = @"<font color=""#008000""> ** 這里是不固定的字符串1 ** </font> <font color=""#008000""> ** 這里是不固定的字符串2 ** </font> <font color=""#008000""> ** 這里是不固定的字符串3 ** </font> "; MatchCollection mc = Regex.Matches(test, @"(?<=<font[\s\S]*?>)([\s\S]*?)(?=</font>)"); foreach (Match m in mc) { richTextBox2.Text += m.Value + "\n---------------\n"; } /*--------輸出-------- ** 這里是不固定的字符串1 ** --------------- <font color="#008000"> ** 這里是不固定的字符串2 ** --------------- <font color="#008000"> ** 這里是不固定的字符串3 ** --------------- */
其實(shí)真正讓人費(fèi)解的是這里的逆序環(huán)視的匹配結(jié)果,為了更好的說(shuō)明問(wèn)題,改下正則。
string test = @"<font color=""#008000""> ** 這里是不固定的字符串1 ** </font>
<font color=""#008000""> ** 這里是不固定的字符串2 ** </font> <font color=""#008000""> ** 這里是不固定的字符串3 ** </font> "; MatchCollection mc = Regex.Matches(test, @"(?<=(<font[\s\S]*?>))([\s\S]*?)(?=</font>)"); for(int i=0;i<mc.Count;i++) { richTextBox2.Text += "第" + (i+1) + "輪成功匹配結(jié)果:\n"; richTextBox2.Text += "Group[0]:" + m.Value + "\n"; richTextBox2.Text += "Group[1]:" + m.Groups[1].Value + "\n---------------\n"; } /*--------輸出-------- 第1輪成功匹配結(jié)果: Group[0]: ** 這里是不固定的字符串1 ** Group[1]:<font color="#008000"> --------------- 第2輪成功匹配結(jié)果: Group[0]: <font color="#008000"> ** 這里是不固定的字符串2 ** Group[1]:<font color="#008000"> ** 這里是不固定的字符串1 ** </font> --------------- 第3輪成功匹配結(jié)果: Group[0]: <font color="#008000"> ** 這里是不固定的字符串3 ** Group[1]:<font color="#008000"> ** 這里是不固定的字符串2 ** </font> ---------------
對(duì)于第一輪成功匹配結(jié)果應(yīng)該不存在什么疑問(wèn),這里不做解釋。
第一輪成功匹配結(jié)束的位置是第一個(gè)“</font>”前的位置,第二輪成功匹配嘗試就是從這一位置開(kāi)始。
首先由“(?<=<font[\s\S]*?>)”取得控制權(quán),向左查找6個(gè)字符后開(kāi)始嘗試匹配,由于“<”會(huì)匹配失敗,所以會(huì)一直嘗試到位置0處,這時(shí)“<font”是可以匹配成功的,但是由于“<font[\s\S]*?>”要匹配成功,匹配的結(jié)束位置必須是第一個(gè)“</font>”前的位置,所以“>”是匹配失敗的,這一位置整個(gè)表達(dá)式匹配失敗。
正則引擎?zhèn)鲃?dòng)裝置向右傳動(dòng),直到第一個(gè)“</font>”后的位置,“<font[\s\S]*?>”匹配成功,匹配開(kāi)始位置是位置0,匹配結(jié)束位置是第一個(gè)“</font>”后的位置,“<font[\s\S]*?>”匹配到的內(nèi)容是“<font color="#008000"> ** 這里是不固定的字符串1 ** </font>”,其中“[\s\S]*?”匹配到的內(nèi)容是“color="#008000"> ** 這里是不固定的字符串1 ** </font”,后面的子表達(dá)式繼續(xù)匹配,直到第二輪匹配成功。
接下來(lái)的第三輪成功匹配,匹配過(guò)程與第二輪基本相同,只不過(guò)由于使用的是非貪婪模式,所以“<font[\s\S]*?>”在匹配到“<font color="#008000"> ** 這里是不固定的字符串2 ** </font>”時(shí)匹配成功,就結(jié)束匹配,不再向左嘗試匹配了。
接下來(lái)看下貪婪模式的匹配結(jié)果。
string test = @"<font color=""#008000""> ** 這里是不固定的字符串1 ** </font> <font color=""#008000""> ** 這里是不固定的字符串2 ** </font> <font color=""#008000""> ** 這里是不固定的字符串3 ** </font> "; MatchCollection mc = Regex.Matches(test, @"(?<=(<font[\s\S]*>))([\s\S]*?)(?=</font>)"); for(int i=0;i<mc.Count;i++) { richTextBox2.Text += "第" + (i+1) + "輪成功匹配結(jié)果:\n"; richTextBox2.Text += "Group[0]:" + m.Value + "\n"; richTextBox2.Text += "Group[1]:" + m.Groups[1].Value + "\n---------------\n"; } /*--------輸出-------- 第1輪匹配結(jié)果: Group[0]: ** 這里是不固定的字符串1 ** Group[1]:<font color="#008000"> --------------- 第2輪匹配結(jié)果: Group[0]: <font color="#008000"> ** 這里是不固定的字符串2 ** Group[1]:<font color="#008000"> ** 這里是不固定的字符串1 ** </font> --------------- 第3輪匹配結(jié)果: Group[0]: <font color="#008000"> ** 這里是不固定的字符串3 ** Group[1]:<font color="#008000"> ** 這里是不固定的字符串1 ** </font> <font color="#008000"> ** 這里是不固定的字符串2 ** </font> --------------- 僅僅是一個(gè)字符的差別,整個(gè)表達(dá)式的匹配結(jié)果沒(méi)有變化,但匹配過(guò)程差別卻是很大的。 那么如果想得到下面這種結(jié)果要如何做呢? /*--------輸出-------- ** 這里是不固定的字符串1 ** --------------- ** 這里是不固定的字符串2 ** --------------- ** 這里是不固定的字符串3 ** --------------- */
把量詞修飾的子表達(dá)式的匹配范圍縮小就可以了。
string test = @"<font color=""#008000""> ** 這里是不固定的字符串1 ** </font> <font color=""#008000""> ** 這里是不固定的字符串2 ** </font> <font color=""#008000""> ** 這里是不固定的字符串3 ** </font> "; MatchCollection mc = Regex.Matches(test, @"(?is)(?<=(<font[^>]*>))(?:(?!</?font\b).)*(?=</font>)"); for(int i=0;i<mc.Count;i++) { richTextBox2.Text += "第" + (i+1) + "輪匹配結(jié)果:\n"; richTextBox2.Text += "Group[0]:" + mc[i].Value + "\n"; richTextBox2.Text += "Group[1]:" + mc[i].Groups[1].Value + "\n---------------\n"; } /*--------輸出-------- 第1輪匹配結(jié)果: Group[0]: ** 這里是不固定的字符串1 ** Group[1]:<font color="#008000"> --------------- 第2輪匹配結(jié)果: Group[0]: ** 這里是不固定的字符串2 ** Group[1]:<font color="#008000"> --------------- 第3輪匹配結(jié)果: Group[0]: ** 這里是不固定的字符串3 ** Group[1]:<font color="#008000"> --------------- */
3.2 逆序環(huán)視應(yīng)用總結(jié)
通過(guò)對(duì)逆序環(huán)視的分析,可以看出,逆序環(huán)視中使用不定長(zhǎng)度的量詞,匹配過(guò)程很復(fù)雜,代價(jià)也是很大的,這也許也是目前絕大多數(shù)語(yǔ)言不支持逆序環(huán)視,或是不支持在逆序環(huán)視中使用不定長(zhǎng)度量詞的原因吧。
在正則應(yīng)用中需要注意的幾點(diǎn):
1、 不要輕易在逆序環(huán)視中使用不定長(zhǎng)度的量詞,除非確實(shí)需要;
2、 在任何場(chǎng)景下,不只是逆序環(huán)視中,不要輕易使用量詞修飾匹配范圍非常大的子表達(dá)式,小數(shù)點(diǎn)“.”和“[\s\S]”之類(lèi)的,使用時(shí)尤其要注意。
到此這篇關(guān)于正則應(yīng)用之 逆序環(huán)視探索 .的文章就介紹到這了,更多相關(guān)逆序環(huán)視內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
正則表達(dá)式的神奇世界之表達(dá)、匹配和提取全解析
這篇文章主要給大家介紹了關(guān)于正則表達(dá)式的神奇世界之表達(dá)、匹配和提取的相關(guān)資料,正則表達(dá)式是由一些特定的字符組成,代表一個(gè)規(guī)則,可以用來(lái)檢驗(yàn)數(shù)據(jù)格式是否合法,也可以在一段文本中查找滿(mǎn)足要求的內(nèi)容,需要的朋友可以參考下2024-02-02正則表達(dá)式中對(duì)各字符集編碼范圍的總結(jié)
正則表達(dá)式中對(duì)各字符集編碼范圍的總結(jié)...2007-03-03正則表達(dá)式匹配(URL、電話(huà)、手機(jī)、郵箱)的實(shí)例代碼
本文通過(guò)實(shí)例代碼給大家介紹了正則表達(dá)式匹配(URL、電話(huà)、手機(jī)、郵箱)的方法,非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧2017-08-08提高正則表達(dá)式性能的幾點(diǎn)實(shí)用建議匯總
正則表達(dá)式是計(jì)算科學(xué)的一個(gè)概念,很多語(yǔ)言都實(shí)現(xiàn)了他,正則表達(dá)式使用一些特定的元字符來(lái)檢索,匹配以及替換符合規(guī)則的字符串,下面這篇文章主要給大家介紹了提高正則表達(dá)式性能的幾點(diǎn)實(shí)用建議,需要的朋友可以參考下2022-08-08JavaScript正則表達(dá)式迷你書(shū)之貪婪模式-學(xué)習(xí)筆記
這篇文章主要介紹了JavaScript正則表達(dá)式迷你書(shū)之貪婪模式-學(xué)習(xí)筆記,需要的朋友可以參考下2020-02-02