正则表达式子常式正则表达式子常式正则表达式子常式正则表达式子常式
  • 文章
  • 正则表达式
    • 工具
  • 登录
找到的结果: {phrase} (显示: {results_count} 共: {results_count_total})
显示: {results_count} 共: {results_count_total}

加载更多搜索结果...

搜索范围
模糊匹配
搜索标题
搜索内容
发表 admin at 2024年3月5日
类别
  • 正则表达式
标签
正则表达式子常式
  • 简
  • 繁
  • En
关于正则表达式 » 正则表达式教程 » 正则表达式子常式

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

正则表达式子常式

Perl 5.10、PCRE 4.0 和 Ruby 1.9 支持正则表达式子常式调用。这些调用与正则表达式递归非常类似。子常式调用不会再次比对整个正则表达式,只会比对捕获组内的正则表达式。您可以在正则表达式的任何位置调用任何捕获组的子常式。如果您在子常式调用的群组内放置调用,您就会有一个递归捕获组。

与正则表达式递归一样,您可以使用各种语法来运行完全相同的事情。Perl 使用 (?1) 调用编号群组,(?+1) 调用下一个群组,(?-1) 调用前一个群组,以及 (?&name) 调用命名组。您可以使用所有这些调用来参照同一个群组。 (?+1)(?'name'[abc])(?1)(?-1)(?&name) 比对长度为五个字母,且仅包含字母表前三个字母的字符串。此正则表达式与 [abc](?'name'[abc])[abc][abc][abc] 完全相同。

PCRE 是第一个支持子程序调用的正则表达式引擎。 (?P<name>[abc])(?1)(?P>name) 匹配三个字母,例如 (?P<name>[abc])[abc][abc]。 (?1) 是调用一个编号群组,而 (?P>name) 是调用一个命名组。后者在 PCRE 手册页中称为「Python 语法」。尽管此语法模仿 Python 用于 命名捕获组 的语法,但这是 PCRE 的发明。Python 不支持子程序调用或递归。PCRE 7.2 添加 (?+1) 和 (?-1) 以进行相对调用。PCRE 7.7 添加 Perl 5.10 和 Ruby 2.0 使用的所有语法。最新版本的 PHP、Delphi 和 R 也支持所有这些语法,因为它们的正则表达式函数是基于 PCRE。

Ruby 1.9 及之后版本使用的语法看起来更像反向引用。 \g<1> 和 \g'1' 调用一个编号群组,\g<name> 和 \g'name' 调用一个命名组,而 \g<-1> 和 \g'-1' 调用前一个群组。Ruby 2.0 添加 \g<+1> 和 \g'+1' 以调用下一个群组。 \g<+1>(?<name>[abc])\g<1>\g<-1>\g<name> 和 \g'+1'(?'name'[abc])\g'1'\g'-1'\g'name' 在 Ruby 2.0 中匹配与 Perl 范例在 Perl 中匹配的相同 5 个字母字符串。带有尖括号和引号的语法可以互换使用。

稍后我们将看到,Perl、PCRE 和 Ruby 在处理子程序调用期间的 截取、反向参考 和 回溯 方面存在差异。尽管它们拷贝了彼此的语法,但它们并没有拷贝彼此的行为。但这些差异不会在这个页面的基本范例中发挥作用。

Boost 1.42 从 Perl 拷贝了语法,但其实作却因错误而受损,这些错误在版本 1.62 中仍未完全修复。最重要的是,除了 * 或 {0,} 之外的量词会导致子程序调用行为异常。这在 Boost 1.60 中已获得部分修复,它也能正确处理 ? 和 {0,1}。

Boost 不支持 Ruby 子程序调用的语法。在 Boost 中,\g<1> 是反向参考(不是子程序调用),用于捕获组 1。因此,([ab])\g<1> 可以匹配 aa 和 bb,但不能匹配 ab 或 ba。在 Ruby 中,相同的正则表达式将匹配所有四个字符串。本教程中讨论的其他风格都不使用此语法作为反向参考。

匹配平衡结构

递归进入捕获组是比递归整个 regex 更灵活的 配对平衡结构 方式。我们可以将 regex 包在捕获组中,递归进入捕获组而非整个 regex,并在捕获组外添加锚点。 \A(b(?:m|(?1))*e)\z 是用来检查字符串是否完全由正确平衡的结构组成的通用 regex。同样地,b 是结构的开头,m 是结构中间可能出现的内容,而 e 是结构结尾可能出现的内容。为了得到正确的结果,b、m 和 e 这三者不应有两个以上可以配对相同的文本。你可以使用 原子组 取代 非捕获组 来提升性能:\A(b(?>m|(?1))*e)\z。

类似地,\Ao*(b(?:m|(?1))*eo*)+\z 和优化的 \Ao*+(b(?>m|(?1))*+eo*+)++\z 会配对一个字符串,该字符串只包含一个或多个正确平衡的结构串行,中间可能穿插其他文本。在此,o 是平衡结构外可能出现的内容。它通常会与 m 相同。 o 不应能配对与 b 或 e 相同的文本。

\A(\((?>[^()]|(?1))*\))\z 符合一个字符串,该字符串仅包含一对平衡的括号,括号之间可能包含文本。 \A[^()]*+(\((?>[^()]|(?1))*+\)[^()]*+)++\z。

比对同一结构超过一次

如果一个正则表达式需要在不同部分比对同一类型的结构(但不是完全相同的文本)超过一次,使用子常式调用会更简短且精简。假设您需要一个正则表达式来比对下列病历数据

Name: John Doe
Born: 17-Jan-1964
Admitted: 30-Jul-2013
Released: 3-Aug-2013

此外,假设您需要准确比对日期格式,因此正则表达式可以筛选出有效的记录,并将无效记录留给人工检查。在大部分正则表达式风格中,您可以轻松使用 自由间距语法 通过这个正则表达式来运行此动作

^Name:\ (.*)\r?\n
Born:\ (?:3[01]|[12][0-9]|[1-9])
       
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
       
-(?:19|20)[0-9][0-9]\r?\n
Admitted:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]\r?\n
Released:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]$

通过子常式调用,您可以让这个正则表达式更短、更容易阅读和维护

^姓名:\ (.*)\r?\n
出生:\ (?'date'(?:3[01]|[12][0-9]|[1-9])
               
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
               
-(?:19|20)[0-9][0-9])\r?\n
入院:\ \g'date'\r?\n
出院:\ \g'date'$

独立子程序定义

在 Perl 和 PCRE 中,您可以使用特殊 DEFINE 群组进一步运行此步骤:(?(DEFINE)(?'subroutine'regex))。虽然这看起来像一个条件式,它参照不存在的群组 DEFINE,其中包含一个单一的名称群组「subroutine」,但 DEFINE 群组是一种特殊语法。固定文本(?(DEFINE)打开群组。括号关闭群组。这个特殊组告诉 regex 引擎忽略其内容,除了解析它以取得已命名和已编号的捕获组。您可以将任意数量的捕获组放入 DEFINE 群组中。DEFINE 群组本身绝不匹配任何内容,而且绝不会无法匹配。它会被完全忽略。regex foo(?(DEFINE)(?'subroutine'skipped))bar匹配foobar。DEFINE 群组在此 regex 中完全多余,因为没有调用其内部的任何群组。

有了 DEFINE 群组,我们的 regex 会变成

(?(DEFINE)(?'date'(?:3[01]|[12][0-9]|[1-9])
                  
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
                  
-(?:19|20)[0-9][0-9]))
^姓名:\ (.*)\r?\n
出生:\ (?P>date)\r?\n
入院:\ (?P>date)\r?\n
出院:\ (?P>date)$

子程序调用上的量词

子程序调用上的量词运作方式就像 递归上的量词。调用会重复运行,直到满足量词为止。 ([abc])(?1){3} 会配对 abcb 和任何其他由前三个字母组合而成的四个字母组合。首先,群组配对一次,然后调用配对三次。此正则表达式等于 ([abc])[abc]{3}。

群组上的量词会被子程序调用忽略。 ([abc]){3}(?1) 也符合 abcb。首先,群组符合三次,因为它有量词。然后子程序调用符合一次,因为它没有量词。 ([abc]){3}(?1){3} 符合六个字母,例如 abbcab,因为现在群组和调用都重复 3 次。这两个正则表达式等于 ([abc]){3}[abc] 和 ([abc]){3}[abc]{3}。

虽然 Ruby 不支持子程序定义群组,但它支持对重复零次的群组进行子程序调用。 (a){0}\g<1>{3} 符合 aaa。群组本身被略过,因为它重复零次。然后子程序调用根据其量词符合三次。这也适用于 PCRE 7.7 及更新版本。它不适用于旧版本的 PCRE 或任何版本的 Perl,因为有错误。

病历范例的 Ruby 版本可以进一步清理为

(?'date'(?:3[01]|[12][0-9]|[1-9])
        
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
        
-(?:19|20)[0-9][0-9]){0}
^姓名:\ (.*)\r?\n
出生:\ \g'date'\r?\n
入院:\ \g'date'\r?\n
出院:\ \g'date'$

正規表示式子常式
  • 简
  • 繁
  • En
關於正規表示式 » 正規表示式教學 » 正規表示式子常式

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

正規表示式子常式

Perl 5.10、PCRE 4.0 和 Ruby 1.9 支援正規表示式子常式呼叫。這些呼叫與正規表示式遞迴非常類似。子常式呼叫不會再次比對整個正規表示式,只會比對擷取群組內的正規表示式。您可以在正規表示式的任何位置呼叫任何擷取群組的子常式。如果您在子常式呼叫的群組內放置呼叫,您就會有一個遞迴擷取群組。

與正規表示式遞迴一樣,您可以使用各種語法來執行完全相同的事情。Perl 使用 (?1) 呼叫編號群組,(?+1) 呼叫下一個群組,(?-1) 呼叫前一個群組,以及 (?&name) 呼叫命名群組。您可以使用所有這些呼叫來參照同一個群組。 (?+1)(?'name'[abc])(?1)(?-1)(?&name) 比對長度為五個字母,且僅包含字母表前三個字母的字串。此正規表示式與 [abc](?'name'[abc])[abc][abc][abc] 完全相同。

PCRE 是第一個支援子程式呼叫的正規表示式引擎。 (?P<name>[abc])(?1)(?P>name) 匹配三個字母,例如 (?P<name>[abc])[abc][abc]。 (?1) 是呼叫一個編號群組,而 (?P>name) 是呼叫一個命名群組。後者在 PCRE 手冊頁中稱為「Python 語法」。儘管此語法模仿 Python 用於 命名擷取群組 的語法,但這是 PCRE 的發明。Python 不支援子程式呼叫或遞迴。PCRE 7.2 新增 (?+1) 和 (?-1) 以進行相對呼叫。PCRE 7.7 新增 Perl 5.10 和 Ruby 2.0 使用的所有語法。最新版本的 PHP、Delphi 和 R 也支援所有這些語法,因為它們的正規表示式函式是基於 PCRE。

Ruby 1.9 及之後版本使用的語法看起來更像反向參照。 \g<1> 和 \g'1' 呼叫一個編號群組,\g<name> 和 \g'name' 呼叫一個命名群組,而 \g<-1> 和 \g'-1' 呼叫前一個群組。Ruby 2.0 新增 \g<+1> 和 \g'+1' 以呼叫下一個群組。 \g<+1>(?<name>[abc])\g<1>\g<-1>\g<name> 和 \g'+1'(?'name'[abc])\g'1'\g'-1'\g'name' 在 Ruby 2.0 中匹配與 Perl 範例在 Perl 中匹配的相同 5 個字母字串。帶有尖括號和引號的語法可以互換使用。

稍後我們將看到,Perl、PCRE 和 Ruby 在處理子程式呼叫期間的 擷取、反向參考 和 回溯 方面存在差異。儘管它們複製了彼此的語法,但它們並沒有複製彼此的行為。但這些差異不會在這個頁面的基本範例中發揮作用。

Boost 1.42 從 Perl 複製了語法,但其實作卻因錯誤而受損,這些錯誤在版本 1.62 中仍未完全修復。最重要的是,除了 * 或 {0,} 之外的量詞會導致子程式呼叫行為異常。這在 Boost 1.60 中已獲得部分修復,它也能正確處理 ? 和 {0,1}。

Boost 不支援 Ruby 子程式呼叫的語法。在 Boost 中,\g<1> 是反向參考(不是子程式呼叫),用於擷取群組 1。因此,([ab])\g<1> 可以匹配 aa 和 bb,但不能匹配 ab 或 ba。在 Ruby 中,相同的正規表示式將匹配所有四個字串。本教學課程中討論的其他風格都不使用此語法作為反向參考。

匹配平衡結構

遞迴進入擷取群組是比遞迴整個 regex 更靈活的 配對平衡結構 方式。我們可以將 regex 包在擷取群組中,遞迴進入擷取群組而非整個 regex,並在擷取群組外新增錨點。 \A(b(?:m|(?1))*e)\z 是用來檢查字串是否完全由正確平衡的結構組成的通用 regex。同樣地,b 是結構的開頭,m 是結構中間可能出現的內容,而 e 是結構結尾可能出現的內容。為了得到正確的結果,b、m 和 e 這三者不應有兩個以上可以配對相同的文字。你可以使用 原子群組 取代 非擷取群組 來提升效能:\A(b(?>m|(?1))*e)\z。

類似地,\Ao*(b(?:m|(?1))*eo*)+\z 和最佳化的 \Ao*+(b(?>m|(?1))*+eo*+)++\z 會配對一個字串,該字串只包含一個或多個正確平衡的結構序列,中間可能穿插其他文字。在此,o 是平衡結構外可能出現的內容。它通常會與 m 相同。 o 不應能配對與 b 或 e 相同的文字。

\A(\((?>[^()]|(?1))*\))\z 符合一個字串,該字串僅包含一對平衡的括號,括號之間可能包含文字。 \A[^()]*+(\((?>[^()]|(?1))*+\)[^()]*+)++\z。

比對同一結構超過一次

如果一個正規表示式需要在不同部分比對同一類型的結構(但不是完全相同的文字)超過一次,使用子常式呼叫會更簡短且精簡。假設您需要一個正規表示式來比對下列病歷資料

Name: John Doe
Born: 17-Jan-1964
Admitted: 30-Jul-2013
Released: 3-Aug-2013

此外,假設您需要準確比對日期格式,因此正規表示式可以篩選出有效的記錄,並將無效記錄留給人工檢查。在大部分正規表示式風味中,您可以輕鬆使用 自由間距語法 透過這個正規表示式來執行此動作

^Name:\ (.*)\r?\n
Born:\ (?:3[01]|[12][0-9]|[1-9])
       
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
       
-(?:19|20)[0-9][0-9]\r?\n
Admitted:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]\r?\n
Released:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]$

透過子常式呼叫,您可以讓這個正規表示式更短、更容易閱讀和維護

^姓名:\ (.*)\r?\n
出生:\ (?'date'(?:3[01]|[12][0-9]|[1-9])
               
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
               
-(?:19|20)[0-9][0-9])\r?\n
入院:\ \g'date'\r?\n
出院:\ \g'date'$

獨立子程式定義

在 Perl 和 PCRE 中,您可以使用特殊 DEFINE 群組進一步執行此步驟:(?(DEFINE)(?'subroutine'regex))。雖然這看起來像一個條件式,它參照不存在的群組 DEFINE,其中包含一個單一的名稱群組「subroutine」,但 DEFINE 群組是一種特殊語法。固定文字(?(DEFINE)開啟群組。括號關閉群組。這個特殊群組告訴 regex 引擎忽略其內容,除了解析它以取得已命名和已編號的擷取群組。您可以將任意數量的擷取群組放入 DEFINE 群組中。DEFINE 群組本身絕不匹配任何內容,而且絕不會無法匹配。它會被完全忽略。regex foo(?(DEFINE)(?'subroutine'skipped))bar匹配foobar。DEFINE 群組在此 regex 中完全多餘,因為沒有呼叫其內部的任何群組。

有了 DEFINE 群組,我們的 regex 會變成

(?(DEFINE)(?'date'(?:3[01]|[12][0-9]|[1-9])
                  
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
                  
-(?:19|20)[0-9][0-9]))
^姓名:\ (.*)\r?\n
出生:\ (?P>date)\r?\n
入院:\ (?P>date)\r?\n
出院:\ (?P>date)$

子程式呼叫上的量詞

子程式呼叫上的量詞運作方式就像 遞迴上的量詞。呼叫會重複執行,直到滿足量詞為止。 ([abc])(?1){3} 會配對 abcb 和任何其他由前三個字母組合而成的四個字母組合。首先,群組配對一次,然後呼叫配對三次。此正規表示式等於 ([abc])[abc]{3}。

群組上的量詞會被子程式呼叫忽略。 ([abc]){3}(?1) 也符合 abcb。首先,群組符合三次,因為它有量詞。然後子程式呼叫符合一次,因為它沒有量詞。 ([abc]){3}(?1){3} 符合六個字母,例如 abbcab,因為現在群組和呼叫都重複 3 次。這兩個正規表示式等於 ([abc]){3}[abc] 和 ([abc]){3}[abc]{3}。

雖然 Ruby 不支援子程式定義群組,但它支援對重複零次的群組進行子程式呼叫。 (a){0}\g<1>{3} 符合 aaa。群組本身被略過,因為它重複零次。然後子程式呼叫根據其量詞符合三次。這也適用於 PCRE 7.7 及更新版本。它不適用於舊版本的 PCRE 或任何版本的 Perl,因為有錯誤。

病歷範例的 Ruby 版本可以進一步清理為

(?'date'(?:3[01]|[12][0-9]|[1-9])
        
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
        
-(?:19|20)[0-9][0-9]){0}
^姓名:\ (.*)\r?\n
出生:\ \g'date'\r?\n
入院:\ \g'date'\r?\n
出院:\ \g'date'$

Regular Expression Subroutines
  • 简
  • 繁
  • En
About Regular Expressions » Regular Expressions Tutorial » Regular Expression Subroutines

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

Regular Expression Subroutines

Perl 5.10, PCRE 4.0, and Ruby 1.9 support regular expression subroutine calls. These are very similar to regular expression recursion. Instead of matching the entire regular expression again, a subroutine call only matches the regular expression inside a capturing group. You can make a subroutine call to any capturing group from anywhere in the regex. If you place a call inside the group that it calls, you’ll have a recursive capturing group.

As with regex recursion, there is a wide variety of syntax that you can use for exactly the same thing. Perl uses (?1) to call a numbered group, (?+1) to call the next group, (?-1) to call the preceding group, and (?&name) to call a named group. You can use all of these to reference the same group. (?+1)(?'name'[abc])(?1)(?-1)(?&name) matches a string that is five letters long and consists only of the first three letters of the alphabet. This regex is exactly the same as [abc](?'name'[abc])[abc][abc][abc].

PCRE was the first regex engine to support subroutine calls. (?P<name>[abc])(?1)(?P>name) matches three letters like (?P<name>[abc])[abc][abc] does. (?1) is a call to a numbered group and (?P>name) is a call to a named group. The latter is called the “Python syntax” in the PCRE man page. While this syntax mimics the syntax Python uses for named capturing groups, it is a PCRE invention. Python does not support subroutine calls or recursion. PCRE 7.2 added (?+1) and (?-1) for relative calls. PCRE 7.7 adds all the syntax used by Perl 5.10 and Ruby 2.0. Recent versions of PHP, Delphi, and R also support all this syntax, as their regex functions are based on PCRE.

The syntax used by Ruby 1.9 and later looks more like that of backreferences. \g<1> and \g'1' call a numbered group, \g<name> and \g'name' call a named group, while \g<-1> and \g'-1' call the preceding group. Ruby 2.0 adds \g<+1> and \g'+1' to call the next group. \g<+1>(?<name>[abc])\g<1>\g<-1>\g<name> and \g'+1'(?'name'[abc])\g'1'\g'-1'\g'name' match the same 5-letter string in Ruby 2.0 as the Perl example does in Perl. The syntax with angle brackets and with quotes can be used interchangeably.

As we’ll see later, there are differences in how Perl, PCRE, and Ruby deal with capturing, backreferences, and backtracking during subroutine calls. While they copied each other’s syntax, they did not copy each other’s behavior. But these differences do not come into play in the basic examples on this page.

Boost 1.42 copied the syntax from Perl but its implementation is marred by bugs, which are still not all fixed in version 1.62. Most significantly, quantifiers other than * or {0,} cause subroutine calls to misbehave. This is partially fixed in Boost 1.60 which correctly handles ? and {0,1} too.

Boost does not support the Ruby syntax for subroutine calls. In Boost \g<1> is a backreference—not a subroutine call—to capturing group 1. So ([ab])\g<1> can match aa and bb but not ab or ba. In Ruby the same regex would match all four strings. No other flavor discussed in this tutorial uses this syntax for backreferences.

Matching Balanced Constructs

Recursion into a capturing group is a more flexible way of matching balanced constructs than recursion of the whole regex. We can wrap the regex in a capturing group, recurse into the capturing group instead of the whole regex, and add anchors outside the capturing group. \A(b(?:m|(?1))*e)\z is the generic regex for checking that a string consists entirely of a correctly balanced construct. Again, b is what begins the construct, m is what can occur in the middle of the construct, and e is what can occur at the end of the construct. For correct results, no two of b, m, and e should be able to match the same text. You can use an atomic group instead of the non-capturing group for improved performance: \A(b(?>m|(?1))*e)\z.

Similarly, \Ao*(b(?:m|(?1))*eo*)+\z and the optimized \Ao*+(b(?>m|(?1))*+eo*+)++\z match a string that consists of nothing but a sequence of one or more correctly balanced constructs, with possibly other text in between. Here, o is what can occur outside the balanced constructs. It will often be the same as m. o should not be able to match the same text as b or e.

\A(\((?>[^()]|(?1))*\))\z matches a string that consists of nothing but a correctly balanced pair of parentheses, possibly with text between them. \A[^()]*+(\((?>[^()]|(?1))*+\)[^()]*+)++\z also allows text before the first opening parenthesis and after the last closing parenthesis in the string.

Matching The Same Construct More Than Once

A regex that needs to match the same kind of construct (but not the exact same text) more than once in different parts of the regex can be shorter and more concise when using subroutine calls. Suppose you need a regex to match patient records like these:

Name: John Doe
Born: 17-Jan-1964
Admitted: 30-Jul-2013
Released: 3-Aug-2013

Further suppose that you need to match the date format rather accurately so the regex can filter out valid records, leaving invalid records for human inspection. In most regex flavors you could easily do this with this regex, using free-spacing syntax:

^Name:\ (.*)\r?\n
Born:\ (?:3[01]|[12][0-9]|[1-9])
       
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
       
-(?:19|20)[0-9][0-9]\r?\n
Admitted:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]\r?\n
Released:\ (?:3[01]|[12][0-9]|[1-9])
           
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
           
-(?:19|20)[0-9][0-9]$

With subroutine calls you can make this regex much shorter, easier to read, and easier to maintain:

^Name:\ (.*)\r?\n
Born:\ (?'date'(?:3[01]|[12][0-9]|[1-9])
               
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
               
-(?:19|20)[0-9][0-9])\r?\n
Admitted:\ \g'date'\r?\n
Released:\ \g'date'$

Separate Subroutine Definitions

In Perl and PCRE, you can take this one step further using the special DEFINE group: (?(DEFINE)(?'subroutine'regex)). While this looks like a conditional that references the non-existent group DEFINE containing a single named group “subroutine”, the DEFINE group is a special syntax. The fixed text (?(DEFINE) opens the group. A parenthesis closes the group. This special group tells the regex engine to ignore its contents, other than to parse it for named and numbered capturing groups. You can put as many capturing groups inside the DEFINE group as you like. The DEFINE group itself never matches anything, and never fails to match. It is completely ignored. The regex foo(?(DEFINE)(?'subroutine'skipped))bar matches foobar. The DEFINE group is completely superfluous in this regex, as there are no calls to any of the groups inside it.

With a DEFINE group, our regex becomes:

(?(DEFINE)(?'date'(?:3[01]|[12][0-9]|[1-9])
                  
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
                  
-(?:19|20)[0-9][0-9]))
^Name:\ (.*)\r?\n
Born:\ (?P>date)\r?\n
Admitted:\ (?P>date)\r?\n
Released:\ (?P>date)$

Quantifiers On Subroutine Calls

Quantifiers on subroutine calls work just like a quantifier on recursion. The call is repeated as many times in sequence as needed to satisfy the quantifier. ([abc])(?1){3} matches abcb and any other combination of four-letter combination of the first three letters of the alphabet. First the group matches once, and then the call matches three times. This regex is equivalent to ([abc])[abc]{3}.

Quantifiers on the group are ignored by the subroutine call. ([abc]){3}(?1) also matches abcb. First, the group matches three times, because it has a quantifier. Then the subroutine call matches once, because it has no quantifier. ([abc]){3}(?1){3} matches six letters, such as abbcab, because now both the group and the call are repeated 3 times. These two regexes are equivalent to ([abc]){3}[abc] and ([abc]){3}[abc]{3}.

While Ruby does not support subroutine definition groups, it does support subroutine calls to groups that are repeated zero times. (a){0}\g<1>{3} matches aaa. The group itself is skipped because it is repeated zero times. Then the subroutine call matches three times, according to its quantifier. This also works in PCRE 7.7 and later. It doesn’t work (reliably) in older versions of PCRE or in any version of Perl because of bugs.

The Ruby version of the patient record example can be further cleaned up as:

(?'date'(?:3[01]|[12][0-9]|[1-9])
        
-(?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)
        
-(?:19|20)[0-9][0-9]){0}
^Name:\ (.*)\r?\n
Born:\ \g'date'\r?\n
Admitted:\ \g'date'\r?\n
Released:\ \g'date'$

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