正規表示式高階用法 分組與捕獲

2021-09-06 06:49:22 字數 4171 閱讀 1457

分組的引入:

對於要重複單個字元,非常簡單,直接在字元後賣弄加上限定符即可,例如 a+ 表示匹配1個或乙個以上的a,a?表示匹配0個或1個a。這些限定符如下所示:

x ?x ,一次或一次也沒有

x *x ,零次或多次

x +x ,一次或多次

x x ,恰好 n 次

x x ,至少 n 次

x x ,至少 n 次,但是不超過 m 次

但是我們如果要對多個字元進行重複怎麼辦呢?此時我們就要用到分組,我們可以使用小括號"()"來指定要重複的子表示式,然後對這個子表示式進行重複,例如:(abc)? 表示0個或1個abc 這裡一 個括號的表示式就表示乙個分組 。

分組可以分為兩種形式,捕獲組和非捕獲組。

捕獲組

捕獲組可以通過從左到右計算其開括號來編號 。例如,在表示式 (a)(b(c)) 中,存在四個這樣的組:

0

(a)(b(c))

1

(a)2

(b(c))

3

(c)組零始終代表整個表示式

之所以這樣命名捕獲組是因為在匹配中,儲存了與這些組匹配的輸入序列的每個子串行。捕獲的子串行稍後可以通過 back 引用(反向引用) 在表示式中使用,也可以在匹配操作完成後從匹配器檢索。

back引用是說在後面的表示式中我們可以使用組的編號來引用前面的表示式所捕獲到的文字序列。注意:反向引用,引用的是前面捕獲組中的文字而不是正則,也就是說反向引用處匹配的文字應和前面捕獲組中的文字相同,這一點很重要。

【例】(["']).*\1  

其中使用了分組,\1就是對引號這個分組的引用,它匹配包含在兩個引號或者兩個單引號中的所有字串,如,"abc" 或 " ' " 或 ' " '  ,但是請注意,它並不會對" a'或者 'a"匹配。原因上面已經說明,back引用只是引用文字而不是表示式。

非捕獲組

以 (?) 開頭的組是純的非捕獲 組,它不捕獲文字 ,也不針對組合計進行計數。就是說,如果小括號中以?號開頭,那麼這個分組就不會捕獲文字,當然也不會有組的編號,因此也不存在back 引用。

我們通過捕獲組就能夠得到我們想要匹配的內容了,那為什麼還要有非捕獲組呢?原因是捕獲組捕獲的內容是被儲存在記憶體中,可供以後使用,比如反向引用就是引用的記憶體中儲存的捕獲組中捕獲的內容。而非捕獲組則不會捕獲文字,也不會將它匹配到的內容單獨分組來放到記憶體中。所以,使用非捕獲組較使用捕獲組更節省記憶體。在實際情況中我們要酌情選用。

1、非捕獲組(?:pattern)

它的作用就是匹配pattern字元,好處就是不捕獲文字,不將匹配到的字元儲存到記憶體中,從而節省記憶體。

【例】匹配indestry或者indestries

我們可以使用indestr(y|ies)或者indestr(?:y|ies)

【例】(?:a|a)123(?:b)可以匹配a123b或者a123b

非捕獲組有很多種形式,其中包括:零寬度斷言和模式修正符

2、零寬度斷言

(?= x )

x ,通過零寬度的正 lookahead

(?! x )

x ,通過零寬度的負 lookahead

(?<= x )

x ,通過零寬度的正 lookbehind

(?x )

x ,通過零寬度的負 lookbehind

這四個非捕獲組用於匹配表示式x,但是不包含表示式的文字。

(?=x )

零寬度正先行斷言。僅當子表示式 x 在 此位置的右側匹配時才繼續匹配。也就是說要使此零寬度斷言起到我們想要的效果的話,就必須把這個非捕獲組放在整個表示式的右側。例如,/w+(?=/d) 與後跟數字的單詞匹配,而不與該數字匹配。此構造不會回溯。

(?!x)

零寬度負先行斷言。僅當子表示式 x 不在 此位置的右側匹配時才繼續匹配。例如,例如,/w+(?!/d) 與後不跟數字的單詞匹配,而不與該數字匹配 。

(?<=x)

零寬度正後發斷言。僅當子表示式 x 在 此位置的左側匹配時才繼續匹配。例如,(?<=19)99 與跟在 19 後面的 99 的例項匹配。此構造不會回溯。

(?零寬度負後發斷言。僅當子表示式 x 不在此位置的左側匹配時才繼續匹配。例如,(?

上面都是理論性的介紹,這裡就使用一些例子來說明一下問題:

【例1】正規表示式 (?含義:匹配後面的文字56前面不能是4,後面必須是9組成。因此,可以匹配如下文字 5569  ,與4569不匹配。

【例2】提取字串 da12bka3434bdca4343bdca234bm中包含在字元a和b之間的數字,但是這個a之前的字元不能是c;b後面的字元必須是d才能提取。

顯然,這裡就只有3434這個數字滿足要求。那麼我們怎麼提取呢?

首先,我們寫出含有捕獲組的正規表示式:[^c]a\d*bd

然後我們再將其變為非捕獲組的正規表示式:(?<=[^c]a)\d*(?=bd)

3、模式修正符

以(?)開頭的非捕獲組除了零寬度斷言之外,還有模式修正符。

正規表示式中常用的模式修正符有i、g、m、s、x、e等。它們之間可以組合搭配使用。

(?imnsx-imnsx: ) 應用或禁用子表示式中指定的選項。例如,(?i-s: ) 將開啟不區分大小寫並禁用單行模式。關閉不區分大小寫的開關可以使用(?-i)。有關更多資訊,請參閱正規表示式選項。

【例1】(?i)ab

表示對(?i)後的所有字元都開啟不區分大小寫的開關。故它可以匹配ab、ab、ab、ab

【例2】(?i:a)b

它表示只對a開啟不區分大小寫的開關。故它可以匹配ab和ab。不能匹配ab和ab。

4(?>pattern)等同於侵占模式

匹配成功不進行回溯,這個比較複雜,與侵占量詞「+」可以通用,比如:\d++ 可以寫為 (?>\d+)。

【例】將一些多位的小數截短到三位小數:\d+\.\d\d[1-9]?\d+

在這種條件下 6.625 能進行匹配,這樣做沒有必要,因為它本身就是三位小數。最後乙個「5」本來是給 [1-9] 匹配的,但是後面還有乙個 \d+ 所以,[1-9] 由於是「?」可以不匹配所以只能放棄當前的匹配,將這個「5」送給 \d+ 去匹配,如果改為:

\d+\.\d\d[1-9]?+\d+

的侵占形式,在「5」匹配到 [1-9] 時,由於是侵占式的,所以不會進行回溯,後面的 \d+ 就匹配不到任東西了,所以導致 6.625 匹配失敗。

這種情況,在替換時就有效了,比如把數字截短到小數點後三位,如果正好是三位小數的,就可以不用替換了,可以提高效率,侵占量詞基本上就是用來提高匹配效率的。

把 \d+\.\d\d[1-9]?+\d+ 改為 \d+\.\d\d(?>[1-9]?)\d+ 這樣是一樣的。

【補充】js獲取分組內容的方法:(可參考js正則例項)

1、 arr[n] = str.match(reg);      或者       arr[n] = reg.exec(str);

返回的匹配陣列arr[n]中,arr[0]表示整個匹配,arr[1],arr[2].......分別表示各個分組的匹配結果

2、通過regexp物件的靜態屬性來獲取

regexp.$1,regexp.$2.........regexp.$9  分別表示匹配到的第乙個分組至第九個分組的內容

例:

var str = "adfasd324232sdfas";

正規表示式 分組與捕獲

之前使用正規表示式的時候大多數狀況下只是用用匹配表示式,為什麼說是匹配表示式呢,因為其實替換文字也可以使用表示式,我稱之為替換表示式。因為通常使用正規表示式的大多會是以下情況,比如把一段文字中的a字串更改為b字串 待匹配文字 abcdabcd 匹配表示式 b 替換文字 e 替換結果 aecdaecd...

正規表示式 分組與捕獲

之前使用正規表示式的時候大多數狀況下只是用用匹配表示式,為什麼說是匹配表示式呢,因為其實替換文字也可以使用表示式,我稱之為替換表示式。因為通常使用正規表示式的大多會是以下情況,比如把一段文字中的a字串更改為b字串 待匹配文字 abcdabcd 匹配表示式 b 替換文字 e 替換結果 aecdaecd...

正規表示式 分組與捕獲

之前使用正規表示式的時候大多數狀況下只是用用匹配表示式,為什麼說是匹配表示式呢,因為其實替換文字也可以使用表示式,我稱之為替換表示式。因為通常使用正規表示式的大多會是以下情況,比如把一段文字中的a字串更改為b字串 待匹配文字 abcdabcd 匹配表示式 b 替換文字 e 替換結果 aecdaecd...