命名捕获组和反向参考命名捕获组和反向参考命名捕获组和反向参考命名捕获组和反向参考
  • 文章
  • 正则表达式
    • 工具
  • 登录
找到的结果: {phrase} (显示: {results_count} 共: {results_count_total})
显示: {results_count} 共: {results_count_total}

加载更多搜索结果...

搜索范围
模糊匹配
搜索标题
搜索内容
发表 admin at 2024年3月5日
类别
  • 正则表达式
标签
命名捕获组和反向参考
  • 简
  • 繁
  • En
关于正则表达式 » 正则表达式教程 » 命名捕获组和反向参考

正则表达式教程
简介
目录
特殊字符
不可打印字符
正则表达式引擎内部
字符类别
字符类别减法
字符类别交集
简写字符类别
点
锚点
字词边界
交替
选用项目
重复
群组和截取
反向参考
反向参考,第 2 部分
命名组
相对反向参考
分支重设群组
自由间距和注解
Unicode
模式修改器
原子组
占有量词
前瞻和后顾
环顾,第 2 部分
将文本保留在比对之外
条件式
平衡组
递归
子常式
无限递归
递归和量词
递归和截取
递归和反向参考
递归和回溯
POSIX 方括号表达式
零长度比对
继续比对
本网站的其他信息
简介
正则表达式快速入门
正则表达式教程
替换字符串教程
应用程序和语言
正则表达式范例
正则表达式参考
替换字符串参考

命名捕获组和反向参考

几乎所有现代正则表达式引擎都支持 编号捕获组 和 编号反向参考。含有大量群组和反向参考的长正则表达式可能难以阅读。它们可能会特别难以维护,因为在正则表达式中间添加或移除捕获组会影响所有添加或移除群组之后的群组编号。

Python 的 re 模块率先提供了解决方案:命名捕获组和命名回溯引用。(?P<name>group) 将 group 的比对结果截取到回溯引用「name」。name 必须是以字母开头的英数字串行。group 可以是任何正则表达式。您可以使用命名回溯引用 (?P=name) 来参照群组的内容。问号、P、尖括号和等号都是语法的组成部分。尽管命名回溯引用的语法使用括号,但它只是一个不会进行任何截取或分组的回溯引用。HTML 标签范例可以写成 <(?P<tag>[A-Z][A-Z0-9]*)\b[^>]*>.*?</(?P=tag)>。

.NET 也支持命名截取。Microsoft 的开发人员发明了自己的语法,而不是遵循 Python 开创并由 PCRE(当时唯一支持命名截取的两个正则表达式引擎)拷贝的语法。(?<name>group) 或 (?'name'group) 将 group 的比对结果截取到回溯引用「name」。命名回溯引用是 \k<name> 或 \k'name'。与 Python 相比,命名组的语法中没有 P。命名回溯引用的语法更类似于编号回溯引用,而不是 Python 使用的语法。您可以在名称周围使用单引号或尖括号。这在正则表达式中完全没有差别。您可以交替使用这两种样式。在使用单引号来界定字符串的编程语言中,建议使用尖括号的语法,而在将正则表达式添加到 XML 文件时,建议使用单引号的语法,因为这可以将您必须运行的转义字符量减到最少,才能将正则表达式格式化为文本字符串或 XML 内容。

由于 Python 和 .NET 引入了自己的语法,因此我们将这两个变体称为命名截取和命名回溯引用的「Python 语法」和「.NET 语法」。如今,许多其他正则表达式风格都拷贝了此语法。

Perl 5.10 添加支持 Python 和 .NET 语法,用于命名截取和反向引用。它还添加了命名反向引用的两种语法变体:\k{one} 和 \g{two}。Perl 中的五种命名反向引用语法之间没有差异。所有语法都可以互换使用。在替换文本中,您可以内插变量 $+{name},以插入由命名捕获组匹配的文本。

PCRE 7.2 和更新版本支持 Perl 5.10 支持的所有命名截取和反向引用语法。旧版本的 PCRE 支持 Python 语法,尽管当时这并「不与 Perl 兼容」。像 PHP、Delphi 和 R 等使用 PCRE 实作其 regex 支持的语言也支持所有这些语法。遗憾的是,PHP 或 R 都不支持替换文本中的命名参照。您必须对命名组使用编号参照。PCRE 完全不支持搜索和替换。

Java 7 和 XRegExp 拷贝了 .NET 语法,但仅拷贝了使用尖括号的变体。Ruby 1.9 支持 .NET 语法的两种变体。

Boost 1.42 和更新版本支持使用 .NET 语法(带尖括号或引号)的命名捕获组,以及使用 Perl 5.10 的 \g 语法(带大括号)的命名反向引用。Boost 1.47 还支持使用 .NET 的 \k 语法(带尖括号和引号)的反向引用。Boost 1.47 允许这些变体相乘。Boost 1.47 允许使用 \g 或 \k 以及大括号、尖括号或引号来指定命名和编号的反向引用。因此,Boost 1.47 和更新版本在基本的 \1 语法之上有六种反向引用语法变体。这使得 Boost 与 Ruby、PCRE、PHP 和 R 发生冲突,后者将带尖括号或引号的 \g 视为 子常式调用。

命名捕获组的数字

不建议混合使用命名和编号的捕获组,因为不同版本在群组编号方式上不一致。如果群组不需要名称,请使用 (?:群组) 语法使其为非截取。在 .NET 中,您可以通过设置 RegexOptions.ExplicitCapture 使所有未命名组为非截取。在 Delphi 中,请设置 roExplicitCapture。在 XRegExp 中,请使用 /n 旗标。 Perl 从 Perl 5.22 开始支持 /n。在 PCRE 中,请设置 PCRE_NO_AUTO_CAPTURE。.NET 支持 (?n) 模式修改子。如果您使所有未命名组为非截取,您可以略过此部分并省去一些麻烦。

大多数版本会从左至右计算命名和未命名捕获组的打开括号,并依序编号。将命名捕获组添加至现有正则表达式仍会影响未命名组的编号。然而,在 .NET 中,未命名捕获组会先被编号,从左至右计算其打开括号,略过所有命名组。之后,命名组会被编号,从左至右计算命名组的打开括号。

举例来说,正则表达式 (a)(?P<x>b)(c)(?P<y>d) 会如预期般比对 abcd。如果您使用此正则表达式和替换 \1\2\3\4 或 $1$2$3$4 (视版本而定) 进行搜索和取代,您将会得到 abcd。所有四个群组都从左至右编号,从一到四。

使用 .NET 时,情况会稍微复杂一点。正则表达式 (a)(?<x>b)(c)(?<y>d) 仍会比对 abcd。不过,如果您使用 $1$2$3$4 进行搜索并取代,您将会得到 acbd。首先,未命名组 (a) 和 (c) 取得数字 1 和 2。然后,命名组「x」和「y」取得数字 3 和 4。

在所有其他拷贝 .NET 语法规则的版本中,正则表达式 (a)(?<x>b)(c)(?<y>d) 仍会比对 abcd。但在所有这些版本中,取代字符串 \1\2\3\4 或 $1$2$3$4(视版本而定)会让您得到 abcd。所有四个群组都从左到右编号。

具有相同名称的多个群组

.NET 架构 允许正则表达式中的多个群组具有相同名称。所有具有相同名称的群组会共用保存其比对文本的相同保存空间。因此,对该名称的反向引用会比对由具有该名称且最近截取到某个项目的群组比对的文本。在取代文本中对名称的参照会插入由具有该名称且最后一个截取到某个项目的群组比对的文本。

Perl 和 Ruby 也允许群组具有相同名称。但这些版本只使用障眼法,让所有具有相同名称的群组看起来像一个群组在作用。实际上,这些群组是分开的。在 Perl 中,反向引用会比对由具有该名称且比对到某个项目的正则表达式中最左边的群组截取的文本。在 Ruby 中,反向引用会比对由具有该名称的任何群组截取的文本。回溯会让 Ruby 尝试所有群组。

因此在 Perl 和 Ruby 中,只有在正则表达式中不同的选项中使用相同名称的群组才有意义,这样才能让具有该名称的群组只有一个能截取任何文本。然后对该群组的反向引用会合理地比对由群组截取的文本。

例如,如果您想要比对「a」后接数字 0..5,或「b」后接数字 4..7,而且您只关心数字,您可以使用正则表达式 a(?<digit>[0-5])|b(?<digit>[4-7])。在这四种风格中,名为「digit」的群组将会提供与字母无关的比对数字 0..7。如果您想要这个比对后接 c 和完全相同的数字,您可以使用 (?:a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>

PCRE 缺省不允许重复命名的群组。PCRE 6.7 及更新版本允许重复命名,只要您打开该选项或使用 模式修改器 (?J)。但在 PCRE 8.36 之前,这并不太实用,因为反向引用总是指向正则表达式中第一个具有该名称的捕获组,而不管它是否参与比对。从 PCRE 8.36(因此 PHP 5.6.9 和 R 3.1.3)以及 PCRE2 开始,反向引用指向实际参与比对的第一个具有该名称的群组。尽管 PCRE 和 Perl 以相反的方向处理重复群组,但如果您遵循建议,仅在不同的选项中使用具有相同名称的群组,则最终结果相同。

Boost 允许重复命名的群组。在 Boost 1.47 之前,这并不实用,因为反向引用总是指向正则表达式中反向引用之前出现的最后一个具有该名称的群组。在 Boost 1.47 及更新版本中,反向引用指向实际参与比对的第一个具有该名称的群组,就像在 PCRE 8.36 及更新版本中一样。

Python、Java 和 XRegExp 3 不允许多个群组使用相同名称。这样做会产生正则表达式编译错误。XRegExp 2 允许重复命名,但无法正确处理。

在 Perl 5.10、PCRE 8.00、PHP 5.2.14 和 Boost 1.42(或这些更新版本)中,当您希望不同选项中的群组具有相同名称时,最好使用 分支重设群组,例如 (?|a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>。使用这种特殊语法(以 (?| 而不是 (?: 开头的群组),两个名为「digit」的群组实际上是一个群组。然后,对该群组的反向引用始终在这些风格之间正确且一致地处理。(旧版本的 PCRE 和 PHP 可能支持分支重设群组,但无法正确处理分支重设群组中的重复名称。)

命名擷取群組和反向參考
  • 简
  • 繁
  • En
關於正規表示式 » 正規表示式教學 » 命名擷取群組和反向參考

正規表示式教學
簡介
目錄
特殊字元
不可列印字元
正規表示式引擎內部
字元類別
字元類別減法
字元類別交集
簡寫字元類別
點
錨點
字詞邊界
交替
選用項目
重複
群組和擷取
反向參考
反向參考,第 2 部分
命名群組
相對反向參考
分支重設群組
自由間距和註解
Unicode
模式修改器
原子群組
佔有量詞
前瞻和後顧
環顧,第 2 部分
將文字保留在比對之外
條件式
平衡群組
遞迴
子常式
無限遞迴
遞迴和量詞
遞迴和擷取
遞迴和反向參考
遞迴和回溯
POSIX 方括號表示式
零長度比對
繼續比對
本網站的其他資訊
簡介
正規表示式快速入門
正規表示式教學
替換字串教學
應用程式和語言
正規表示式範例
正規表示式參考
替換字串參考

命名擷取群組和反向參考

幾乎所有現代正規表示式引擎都支援 編號擷取群組 和 編號反向參考。含有大量群組和反向參考的長正規表示式可能難以閱讀。它們可能會特別難以維護,因為在正規表示式中間新增或移除擷取群組會影響所有新增或移除群組之後的群組編號。

Python 的 re 模組率先提供了解決方案:命名擷取群組和命名回溯引用。(?P<name>group) 將 group 的比對結果擷取到回溯引用「name」。name 必須是以字母開頭的英數字序列。group 可以是任何正規表示式。您可以使用命名回溯引用 (?P=name) 來參照群組的內容。問號、P、尖括號和等號都是語法的組成部分。儘管命名回溯引用的語法使用括號,但它只是一個不會進行任何擷取或分組的回溯引用。HTML 標籤範例可以寫成 <(?P<tag>[A-Z][A-Z0-9]*)\b[^>]*>.*?</(?P=tag)>。

.NET 也支援命名擷取。Microsoft 的開發人員發明了自己的語法,而不是遵循 Python 開創並由 PCRE(當時唯一支援命名擷取的兩個正規表示式引擎)複製的語法。(?<name>group) 或 (?'name'group) 將 group 的比對結果擷取到回溯引用「name」。命名回溯引用是 \k<name> 或 \k'name'。與 Python 相比,命名群組的語法中沒有 P。命名回溯引用的語法更類似於編號回溯引用,而不是 Python 使用的語法。您可以在名稱周圍使用單引號或尖括號。這在正規表示式中完全沒有差別。您可以交替使用這兩種樣式。在使用單引號來界定字串的程式語言中,建議使用尖括號的語法,而在將正規表示式新增到 XML 檔案時,建議使用單引號的語法,因為這可以將您必須執行的跳脫字元量減到最少,才能將正規表示式格式化為文字字串或 XML 內容。

由於 Python 和 .NET 引入了自己的語法,因此我們將這兩個變體稱為命名擷取和命名回溯引用的「Python 語法」和「.NET 語法」。如今,許多其他正規表示式風格都複製了此語法。

Perl 5.10 新增支援 Python 和 .NET 語法,用於命名擷取和反向參照。它還新增了命名反向參照的兩種語法變體:\k{one} 和 \g{two}。Perl 中的五種命名反向參照語法之間沒有差異。所有語法都可以互換使用。在替換文字中,您可以內插變數 $+{name},以插入由命名擷取群組匹配的文字。

PCRE 7.2 和更新版本支援 Perl 5.10 支援的所有命名擷取和反向參照語法。舊版本的 PCRE 支援 Python 語法,儘管當時這並「不與 Perl 相容」。像 PHP、Delphi 和 R 等使用 PCRE 實作其 regex 支援的語言也支援所有這些語法。遺憾的是,PHP 或 R 都不支援替換文字中的命名參照。您必須對命名群組使用編號參照。PCRE 完全不支援搜尋和替換。

Java 7 和 XRegExp 複製了 .NET 語法,但僅複製了使用尖括號的變體。Ruby 1.9 支援 .NET 語法的兩種變體。

Boost 1.42 和更新版本支援使用 .NET 語法(帶尖括號或引號)的命名擷取群組,以及使用 Perl 5.10 的 \g 語法(帶大括號)的命名反向參照。Boost 1.47 還支援使用 .NET 的 \k 語法(帶尖括號和引號)的反向參照。Boost 1.47 允許這些變體相乘。Boost 1.47 允許使用 \g 或 \k 以及大括號、尖括號或引號來指定命名和編號的反向參照。因此,Boost 1.47 和更新版本在基本的 \1 語法之上有六種反向參照語法變體。這使得 Boost 與 Ruby、PCRE、PHP 和 R 發生衝突,後者將帶尖括號或引號的 \g 視為 子常式呼叫。

命名擷取群組的數字

不建議混合使用命名和編號的擷取群組,因為不同版本在群組編號方式上不一致。如果群組不需要名稱,請使用 (?:群組) 語法使其為非擷取。在 .NET 中,您可以透過設定 RegexOptions.ExplicitCapture 使所有未命名群組為非擷取。在 Delphi 中,請設定 roExplicitCapture。在 XRegExp 中,請使用 /n 旗標。 Perl 從 Perl 5.22 開始支援 /n。在 PCRE 中,請設定 PCRE_NO_AUTO_CAPTURE。.NET 支援 (?n) 模式修改子。如果您使所有未命名群組為非擷取,您可以略過此部分並省去一些麻煩。

大多數版本會從左至右計算命名和未命名擷取群組的開啟括號,並依序編號。將命名擷取群組新增至現有正規表示式仍會影響未命名群組的編號。然而,在 .NET 中,未命名擷取群組會先被編號,從左至右計算其開啟括號,略過所有命名群組。之後,命名群組會被編號,從左至右計算命名群組的開啟括號。

舉例來說,正規表示式 (a)(?P<x>b)(c)(?P<y>d) 會如預期般比對 abcd。如果您使用此正規表示式和替換 \1\2\3\4 或 $1$2$3$4 (視版本而定) 進行搜尋和取代,您將會得到 abcd。所有四個群組都從左至右編號,從一到四。

使用 .NET 時,情況會稍微複雜一點。正規表示式 (a)(?<x>b)(c)(?<y>d) 仍會比對 abcd。不過,如果您使用 $1$2$3$4 進行搜尋並取代,您將會得到 acbd。首先,未命名群組 (a) 和 (c) 取得數字 1 和 2。然後,命名群組「x」和「y」取得數字 3 和 4。

在所有其他複製 .NET 語法規則的版本中,正規表示式 (a)(?<x>b)(c)(?<y>d) 仍會比對 abcd。但在所有這些版本中,取代字串 \1\2\3\4 或 $1$2$3$4(視版本而定)會讓您得到 abcd。所有四個群組都從左到右編號。

具有相同名稱的多個群組

.NET 架構 允許正規表示式中的多個群組具有相同名稱。所有具有相同名稱的群組會共用儲存其比對文字的相同儲存空間。因此,對該名稱的反向參照會比對由具有該名稱且最近擷取到某個項目的群組比對的文字。在取代文字中對名稱的參照會插入由具有該名稱且最後一個擷取到某個項目的群組比對的文字。

Perl 和 Ruby 也允許群組具有相同名稱。但這些版本只使用障眼法,讓所有具有相同名稱的群組看起來像一個群組在作用。實際上,這些群組是分開的。在 Perl 中,反向參照會比對由具有該名稱且比對到某個項目的正規表示式中最左邊的群組擷取的文字。在 Ruby 中,反向參照會比對由具有該名稱的任何群組擷取的文字。回溯會讓 Ruby 嘗試所有群組。

因此在 Perl 和 Ruby 中,只有在正規表示式中不同的選項中使用相同名稱的群組才有意義,這樣才能讓具有該名稱的群組只有一個能擷取任何文字。然後對該群組的反向參照會合理地比對由群組擷取的文字。

例如,如果您想要比對「a」後接數字 0..5,或「b」後接數字 4..7,而且您只關心數字,您可以使用正規表示式 a(?<digit>[0-5])|b(?<digit>[4-7])。在這四種風味中,名為「digit」的群組將會提供與字母無關的比對數字 0..7。如果您想要這個比對後接 c 和完全相同的數字,您可以使用 (?:a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>

PCRE 預設不允許重複命名的群組。PCRE 6.7 及更新版本允許重複命名,只要您開啟該選項或使用 模式修改器 (?J)。但在 PCRE 8.36 之前,這並不太實用,因為反向參照總是指向正規表示式中第一個具有該名稱的擷取群組,而不管它是否參與比對。從 PCRE 8.36(因此 PHP 5.6.9 和 R 3.1.3)以及 PCRE2 開始,反向參照指向實際參與比對的第一個具有該名稱的群組。儘管 PCRE 和 Perl 以相反的方向處理重複群組,但如果您遵循建議,僅在不同的選項中使用具有相同名稱的群組,則最終結果相同。

Boost 允許重複命名的群組。在 Boost 1.47 之前,這並不實用,因為反向參照總是指向正規表示式中反向參照之前出現的最後一個具有該名稱的群組。在 Boost 1.47 及更新版本中,反向參照指向實際參與比對的第一個具有該名稱的群組,就像在 PCRE 8.36 及更新版本中一樣。

Python、Java 和 XRegExp 3 不允許多個群組使用相同名稱。這樣做會產生正規表示式編譯錯誤。XRegExp 2 允許重複命名,但無法正確處理。

在 Perl 5.10、PCRE 8.00、PHP 5.2.14 和 Boost 1.42(或這些更新版本)中,當您希望不同選項中的群組具有相同名稱時,最好使用 分支重設群組,例如 (?|a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>。使用這種特殊語法(以 (?| 而不是 (?: 開頭的群組),兩個名為「digit」的群組實際上是一個群組。然後,對該群組的反向參照始終在這些風味之間正確且一致地處理。(舊版本的 PCRE 和 PHP 可能支援分支重設群組,但無法正確處理分支重設群組中的重複名稱。)

Named Capturing Groups and Backreferences
  • 简
  • 繁
  • En
About Regular Expressions » Regular Expressions Tutorial » Named Capturing Groups and Backreferences

Regex Tutorial
Introduction
Table of Contents
Special Characters
Non-Printable Characters
Regex Engine Internals
Character Classes
Character Class Subtraction
Character Class Intersection
Shorthand Character Classes
Dot
Anchors
Word Boundaries
Alternation
Optional Items
Repetition
Grouping & Capturing
Backreferences
Backreferences, part 2
Named Groups
Relative Backreferences
Branch Reset Groups
Free-Spacing & Comments
Unicode
Mode Modifiers
Atomic Grouping
Possessive Quantifiers
Lookahead & Lookbehind
Lookaround, part 2
Keep Text out of The Match
Conditionals
Balancing Groups
Recursion
Subroutines
Infinite Recursion
Recursion & Quantifiers
Recursion & Capturing
Recursion & Backreferences
Recursion & Backtracking
POSIX Bracket Expressions
Zero-Length Matches
Continuing Matches
More on This Site
Introduction
Regular Expressions Quick Start
Regular Expressions Tutorial
Replacement Strings Tutorial
Applications and Languages
Regular Expressions Examples
Regular Expressions Reference
Replacement Strings Reference

Named Capturing Groups and Backreferences

Nearly all modern regular expression engines support numbered capturing groups and numbered backreferences. Long regular expressions with lots of groups and backreferences may be hard to read. They can be particularly difficult to maintain as adding or removing a capturing group in the middle of the regex upsets the numbers of all the groups that follow the added or removed group.

Python’s re module was the first to offer a solution: named capturing groups and named backreferences. (?P<name>group) captures the match of group into the backreference “name”. name must be an alphanumeric sequence starting with a letter. group can be any regular expression. You can reference the contents of the group with the named backreference (?P=name). The question mark, P, angle brackets, and equals signs are all part of the syntax. Though the syntax for the named backreference uses parentheses, it’s just a backreference that doesn’t do any capturing or grouping. The HTML tags example can be written as <(?P<tag>[A-Z][A-Z0-9]*)\b[^>]*>.*?</(?P=tag)>.

.NET also supports named capture. Microsoft’s developers invented their own syntax, rather than follow the one pioneered by Python and copied by PCRE (the only two regex engines that supported named capture at that time). (?<name>group) or (?'name'group) captures the match of group into the backreference “name”. The named backreference is \k<name> or \k'name'. Compared with Python, there is no P in the syntax for named groups. The syntax for named backreferences is more similar to that of numbered backreferences than to what Python uses. You can use single quotes or angle brackets around the name. This makes absolutely no difference in the regex. You can use both styles interchangeably. The syntax using angle brackets is preferable in programming languages that use single quotes to delimit strings, while the syntax using single quotes is preferable when adding your regex to an XML file, as this minimizes the amount of escaping you have to do to format your regex as a literal string or as XML content.

Because Python and .NET introduced their own syntax, we refer to these two variants as the “Python syntax” and the “.NET syntax” for named capture and named backreferences. Today, many other regex flavors have copied this syntax.

Perl 5.10 added support for both the Python and .NET syntax for named capture and backreferences. It also adds two more syntactic variants for named backreferences: \k{one} and \g{two}. There’s no difference between the five syntaxes for named backreferences in Perl. All can be used interchangeably. In the replacement text, you can interpolate the variable $+{name} to insert the text matched by a named capturing group.

PCRE 7.2 and later support all the syntax for named capture and backreferences that Perl 5.10 supports. Old versions of PCRE supported the Python syntax, even though that was not “Perl-compatible” at the time. Languages like PHP, Delphi, and R that implement their regex support using PCRE also support all this syntax. Unfortunately, neither PHP or R support named references in the replacement text. You’ll have to use numbered references to the named groups. PCRE does not support search-and-replace at all.

Java 7 and XRegExp copied the .NET syntax, but only the variant with angle brackets. Ruby 1.9 and supports both variants of the .NET syntax.

Boost 1.42 and later support named capturing groups using the .NET syntax with angle brackets or quotes and named backreferences using the \g syntax with curly braces from Perl 5.10. Boost 1.47 additionally supports backreferences using the \k syntax with angle brackets and quotes from .NET. Boost 1.47 allowed these variants to multiply. Boost 1.47 allows named and numbered backreferences to be specified with \g or \k and with curly braces, angle brackets, or quotes. So Boost 1.47 and later have six variations of the backreference syntax on top of the basic \1 syntax. This puts Boost in conflict with Ruby, PCRE, PHP and R which treat \g with angle brackets or quotes as a subroutine call.

Numbers for Named Capturing Groups

Mixing named and numbered capturing groups is not recommended because flavors are inconsistent in how the groups are numbered. If a group doesn’t need to have a name, make it non-capturing using the (?:group) syntax. In .NET you can make all unnamed groups non-capturing by setting RegexOptions.ExplicitCapture. In Delphi, set roExplicitCapture. With XRegExp, use the /n flag. Perl supports /n starting with Perl 5.22. With PCRE, set PCRE_NO_AUTO_CAPTURE. .NET support the (?n) mode modifier. If you make all unnamed groups non-capturing, you can skip this section and save yourself a headache.

Most flavors number both named and unnamed capturing groups by counting their opening parentheses from left to right. Adding a named capturing group to an existing regex still upsets the numbers of the unnamed groups. In .NET, however, unnamed capturing groups are assigned numbers first, counting their opening parentheses from left to right, skipping all named groups. After that, named groups are assigned the numbers that follow by counting the opening parentheses of the named groups from left to right.

As an example, the regex (a)(?P<x>b)(c)(?P<y>d) matches abcd as expected. If you do a search-and-replace with this regex and the replacement \1\2\3\4 or $1$2$3$4 (depending on the flavor), you will get abcd. All four groups were numbered from left to right, from one till four.

Things are a bit more complicated with .NET. The regex (a)(?<x>b)(c)(?<y>d) again matches abcd. However, if you do a search-and-replace with $1$2$3$4 as the replacement, you will get acbd. First, the unnamed groups (a) and (c) got the numbers 1 and 2. Then the named groups “x” and “y” got the numbers 3 and 4.

In all other flavors that copied the .NET syntax the regex (a)(?<x>b)(c)(?<y>d) still matches abcd. But in all those flavors, the replacement \1\2\3\4 or $1$2$3$4 (depending on the flavor) gets you abcd. All four groups were numbered from left to right.

Multiple Groups with The Same Name

The .NET framework allow multiple groups in the regular expression to have the same name. All groups with the same name share the same storage for the text they match. Thus, a backreference to that name matches the text that was matched by the group with that name that most recently captured something. A reference to the name in the replacement text inserts the text matched by the group with that name that was the last one to capture something.

Perl and Ruby also allow groups with the same name. But these flavors only use smoke and mirrors to make it look like the all the groups with the same name act as one. In reality, the groups are separate. In Perl, a backreference matches the text captured by the leftmost group in the regex with that name that matched something. In Ruby, a backreference matches the text captured by any of the groups with that name. Backtracking makes Ruby try all the groups.

So in Perl and Ruby, you can only meaningfully use groups with the same name if they are in separate alternatives in the regex, so that only one of the groups with that name could ever capture any text. Then backreferences to that group sensibly match the text captured by the group.

For example, if you want to match “a” followed by a digit 0..5, or “b” followed by a digit 4..7, and you only care about the digit, you could use the regex a(?<digit>[0-5])|b(?<digit>[4-7]). In these four flavors, the group named “digit” will then give you the digit 0..7 that was matched, regardless of the letter. If you want this match to be followed by c and the exact same digit, you could use (?:a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>

PCRE does not allow duplicate named groups by default. PCRE 6.7 and later allow them if you turn on that option or use the mode modifier (?J). But prior to PCRE 8.36 that wasn’t very useful as backreferences always pointed to the first capturing group with that name in the regex regardless of whether it participated in the match. Starting with PCRE 8.36 (and thus PHP 5.6.9 and R 3.1.3) and also in PCRE2, backreferences point to the first group with that name that actually participated in the match. Though PCRE and Perl handle duplicate groups in opposite directions the end result is the same if you follow the advice to only use groups with the same name in separate alternatives.

Boost allows duplicate named groups. Prior to Boost 1.47 that wasn’t useful as backreferences always pointed to the last group with that name that appears before the backreference in the regex. In Boost 1.47 and later backreferences point to the first group with that name that actually participated in the match just like in PCRE 8.36 and later.

Python, Java, and XRegExp 3 do not allow multiple groups to use the same name. Doing so will give a regex compilation error. XRegExp 2 allowed them, but did not handle them correctly.

In Perl 5.10, PCRE 8.00, PHP 5.2.14, and Boost 1.42 (or later versions of these) it is best to use a branch reset group when you want groups in different alternatives to have the same name, as in (?|a(?<digit>[0-5])|b(?<digit>[4-7]))c\k<digit>. With this special syntax—group opened with (?| instead of (?:—the two groups named “digit” really are one and the same group. Then backreferences to that group are always handled correctly and consistently between these flavors. (Older versions of PCRE and PHP may support branch reset groups, but don’t correctly handle duplicate names in branch reset groups.)

©2015-2025 艾丽卡 support@alaica.com