快速入門
教學
工具和語言
範例
參考
書籍評論
正規表示式教學
簡介
目錄
特殊字元
不可列印字元
正規表示式引擎內部結構
字元類別
字元類別減法
字元類別交集
簡寫字元類別
錨點
字詞邊界
交替
選用項目
重複
群組和擷取
反向參照
反向參照,第 2 部分
命名群組
相對反向參照
分支重設群組
自由間距和註解
Unicode
模式修改器
原子群組
獨佔量詞
前瞻和後顧
環顧,第 2 部分
將文字保留在比對之外
條件
平衡群組
遞迴
子常式
無限遞迴
遞迴和量詞
遞迴和擷取
遞迴和反向參照
遞迴和回溯
POSIX 方括號表示式
零長度比對
繼續比對
本網站的更多內容
簡介
正規表示式快速入門
正規表示式教學
替換字串教學
應用程式和語言
正規表示式範例
正規表示式參考
替換字串參考
書籍評論
可列印 PDF
關於本網站
RSS Feed 和部落格
RegexBuddy—Better than a regular expression tutorial!

分支重設群組

Perl 5.10 引進了一項新的正規表示式功能,稱為分支重設群組。 JGsoft V2PCRE 7.2 及更新版本也支援此功能,還有像 PHPDelphiR 等基於 PCRE 的正規表示式函數的語言。 Boost 在 1.42 版中將其加入 ECMAScript 語法。

交替在分支重置群組內部共享相同的擷取群組。語法為 (?|正規表示法),其中 (?| 開啟群組,而 正規表示法 為任何正規表示法。如果您未在分支重置群組內部使用任何交替或擷取群組,則其特殊功能不會發揮作用。它隨後會作為 非擷取群組 運作。

正規表示法 (?|(a)|(b)|(c)) 包含一個具有三個交替選項的分支重置群組。此正規表示法會比對 abc。正規表示法只有一個編號為 1 的擷取群組,由所有三個交替選項共享。比對後,$1 會包含 abc

將其與缺乏分支重置群組的正規表示法 (a)|(b)|(c) 進行比較。此正規表示法也會比對 abc。但它有三個擷取群組。比對後,$1 會包含 a 或什麼都不包含,$2 會包含 b 或什麼都不包含,而 $3 會包含 c 或什麼都不包含。

反向參照在分支重置群組內部的擷取群組會依照您的預期運作。 (?|(a)|(b)|(c))\1 會比對 aabbcc。由於分支重置群組內部只有一個交替選項可以比對,因此參與比對的交替選項會決定擷取群組儲存的文字,進而決定反向參照比對的文字。

分支重設群組中的替代方案不需要有相同數量的擷取群組。 (?|abc|(d)(e)(f)|g(h)i) 有三個擷取群組。當此正規表示法符合 abc 時,所有三個群組都是空的。當 def 符合時,$1 包含 d$2 包含 e$3 包含 f。當 ghi 符合時,$1 包含 h,而其他兩個是空的。

您可以在分支重置群組之前和之後使用擷取群組。分支重置群組之前的群組會依通常方式編號。分支重置群組中的群組會從分支重置群組之前的群組繼續編號,每個選項都會重設編號。分支重置群組之後的群組會從具有最多群組的選項繼續編號,即使那不是最後一個選項。因此 (x)(?|abc|(d)(e)(f)|g(h)i)(y) 定義了五個擷取群組。 (x) 是群組 1,(d)(h) 是群組 2,(e) 是群組 3,(f) 是群組 4,以及 (y) 是群組 5。

分支重置群組中的命名擷取群組

您可以在分支重置群組中使用 命名擷取群組。如果您這樣做,您應該對將取得相同編號的群組使用相同的名稱。否則,您會在 Perl 或 Boost 中得到不想要的行為。PowerGREP 將不匹配的群組名稱視為錯誤。PCRE 僅從版本 8.00 開始可靠地支援分支重置群組中的命名群組。這表示 Delphi 僅從 XE7 開始支援,而 PHP 則從版本 5.2.14 開始支援。

(?'before'x)(?|abc|(?'left'd)(?'middle'e)(?'right'f)|g(?'left'h)i)(?'after'y) 與前一個正規表示式相同。它將五個群組命名為「before」、「left」、「middle」、「right」和「after」。請注意,由於第 3 個選項只有一個擷取群組,因此那必須是其他選項中第一個群組的名稱。

如果您省略某些替代方案中的名稱,群組仍會與其他替代方案共用名稱。在正規表示式 (?'before'x)(?|abc|(?'left'd)(?'middle'e)(?'right'f)|g(h)i)(?'after'y) 中,群組 (h) 仍命名為「left」,因為分支重設群組使其共用 (?'left'd) 的名稱和編號。

在 Perl、PCRE 和 Boost 中,當您希望不同替代方案中的群組擁有相同名稱時,最好使用分支重設群組。這是 Perl、PCRE 和 Boost 中確保具有相同名稱的群組實際上是同一個群組的唯一方法。

在 PowerGREP 中,具有相同名稱的群組始終被視為同一個群組。因此,在 PowerGREP 中使用命名擷取群組時,您不必使用分支重設群組。

具有準確天數的日期和月份

現在是更實用的範例。這兩個正規表示式會比對 m/d 或 mm/dd 格式的日期。它們會排除無效日期,例如 2/31。

^(?:(0?[13578]|1[02])/(3[01]|[12][0-9]|0?[1-9]) # 31 天
 
|  (0?[469]|11)/(30|[12][0-9]|0?[1-9])         # 30 天
 
|  (0?2)/([12][0-9]|0?[1-9])                   # 29 天
 
)$

第一個版本使用 非擷取群組 (?:…) 來群組選項。它有六個獨立的擷取群組。 $1$2 保留 31 天月份的月份和日期。 $3$4 保留 30 天月份的月份和日期。 $5$6 僅用於二月。

^(?|(0?[13578]|1[02])/(3[01]|[12][0-9]|0?[1-9]) # 31 天
 
|  (0?[469]|11)/(30|[12][0-9]|0?[1-9])         # 30 天
 
|  (0?2)/([12][0-9]|0?[1-9])                   # 29 天
 
)$

第二個版本使用分支重置群組 (?|…) 來群組備選項並合併其擷取群組。這兩個正規表示式的第 4 個字元是唯一的不同。現在只有兩個擷取群組。它們在樹狀備選項之間共用。當找到一個符合項時,$1 永遠包含月份,而 2 永遠包含日期,與月份中的天數無關。