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

加载更多搜索结果...

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

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

递归中的量词

递归简介显示 a(?R)?z 如何比对 aaazzz。量词 ?使前一个代币成为选用。换句话说,它重复代币 0 到 1 次。在 a(?R)?z 中,(?R) 由其后面的 ? 变成选用。您可能会疑惑,为什么正则表达式尝试递归三次,而不是一次或根本不尝试。

原因是,在递归时,正则表达式引擎会重新开始尝试整个正则表达式。除了引擎会在字符串中前进之外,所有量词和选项的行为就像递归之前的比对进程从未发生过一样。正则表达式引擎会在退出递归时还原所有量词和选项的状态,无论递归是否比对成功。基本上,比对进程会正常继续,就像递归从未发生过一样,除了引擎会在字符串中前进之外。

如果您熟悉进程设计语言,正则表达式递归基本上是一个递归函数调用,而量词是函数中的局部变量。函数的每个递归都会取得自己的局部变量集,这些变量不会影响堆栈中较高层级的递归中的相同局部变量,也不会受到这些变量影响。递归中的量词在所有版本中都是这样运作的,Boost 除外。

让我们看看 a(?R){3}z|q 的行为(Boost 除外)。最简单的可能配对是 q,由正则表达式的第二个选项找到。

第一个选项配对的最简单配对是 aqqqz。在 a 配对后,正则表达式引擎开始递归。 a 无法配对 q。引擎仍在递归中,尝试第二个选项。 q 配对 q。引擎以成功的配对退出递归。引擎现在注意到量词 {3} 已成功重复一次。它需要再重复两次,因此引擎开始另一个递归。它再次配对 q。在量词的第三次迭代中,第三次递归配对 q。最后,z 配对 z,找到整体配对。

这个正则表达式不配对 aqqz 或 aqqqqz。 aqqz 失败,因为在量词的第三次迭代中,递归无法配对 z。 aqqqqz 失败,因为在 a(?R){3} 已配对 aqqq 之后,z 无法配对第四个 q。

正则表达式可以配对较长的字符串,例如 aqaqqqzqz。对于这个字符串,在量词的第二次迭代中,递归配对 aqqqz。由于每个递归都分别追踪量词,因此递归需要连续三次递归才能满足量词的自身实例。这可能导致任意长的配对,例如 aaaqqaqqqzzaqqqzqzqaqqaaqqqzqqzzz。

Boost 如何处理递归中的量词

Boost 对量词在递归中的运作方式有自己的想法。递归仅在 Boost 中与其他版本中相同,如果递归操作符完全没有量词,或者如果它有 * 作为其量词。任何其他量词都可能导致 Boost 1.59 或更早版本与 Boost 1.60 及更高版本相较于其他正则表达式版本有非常不同的配对(或缺乏配对)。Boost 1.60 尝试修复 Boost 和其他版本之间的一些差异,但它只导致不同的不兼容行为。

在 Boost 1.59 及之前版本中,递归量词会计算整个递归堆栈中的迭代和递归次数。因此,在 Boost 1.59 中,a(?R){3}z|q 的可能匹配项包括 aaaazzzz、aaaqzzz、aaqqzz、aaqzqz 和 aqaqzzz。在所有这些匹配项中,递归和迭代的次数加起来等于 3。其他版本不会找到这些匹配项,因为它们需要在每次递归期间进行 3 次迭代。因此,其他版本可以匹配类似 aaqqqzaqqqzaqqqzz 或 aqqaqqqzz 的字符串。Boost 1.59 仅会在这些字符串中匹配 aqqqz。

Boost 1.60 尝试像其他版本一样在每个递归层级迭代量词,但运行方式不正确。任何使递归为可选的量词都允许多次重复。因此,Boost 1.60 和更新版本会将 a(?R)?z 视为与 a(?R)*z 相同。虽然这修正了 a(?R)?z 在 Boost 1.59 中无法完全匹配 aaazzz 的问题,但它也允许其他版本无法使用此正则表达式找到的匹配项,例如 aazazz。如果量词不是可选的,则 Boost 1.60 仅允许它在第一次递归期间匹配。因此,a(?R){3}z|q 只能匹配 q 或 aqqqz。

Boost 在递归量词上的问题也会影响递归标记的父群组上的量词。它们也会影响子常式调用上的量词,以及包含子常式调用到具有量词的群组的父群组的群组上的量词。

递归中其他标记上的量词

正则表达式中其他标记上的量词在递归期间会正常运作。它们会在每次递归中分别追踪其迭代。因此,a{2}(?R)z|q 会匹配 aaqz、aaaaqzz、aaaaaaqzzz 等。在每次递归期间,a 都必须匹配两次。

像这样位于递归中但不会重复递归本身的量词在 Boost 中确实可以正确运作。

遞迴中的量詞
  • 简
  • 繁
  • En
關於正規表示式 » 正規表示式教學 » 遞迴中的量詞

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

遞迴中的量詞

遞迴簡介顯示 a(?R)?z 如何比對 aaazzz。量詞 ?使前一個代幣成為選用。換句話說,它重複代幣 0 到 1 次。在 a(?R)?z 中,(?R) 由其後面的 ? 變成選用。您可能會疑惑,為什麼正則表達式嘗試遞迴三次,而不是一次或根本不嘗試。

原因是,在遞迴時,正則表達式引擎會重新開始嘗試整個正則表達式。除了引擎會在字串中前進之外,所有量詞和選項的行為就像遞迴之前的比對程序從未發生過一樣。正則表達式引擎會在退出遞迴時還原所有量詞和選項的狀態,無論遞迴是否比對成功。基本上,比對程序會正常繼續,就像遞迴從未發生過一樣,除了引擎會在字串中前進之外。

如果您熟悉程序設計語言,正則表達式遞迴基本上是一個遞迴函式呼叫,而量詞是函式中的局部變數。函式的每個遞迴都會取得自己的局部變數集,這些變數不會影響堆疊中較高層級的遞迴中的相同局部變數,也不會受到這些變數影響。遞迴中的量詞在所有版本中都是這樣運作的,Boost 除外。

讓我們看看 a(?R){3}z|q 的行為(Boost 除外)。最簡單的可能配對是 q,由正規表示式的第二個選項找到。

第一個選項配對的最簡單配對是 aqqqz。在 a 配對後,正規表示式引擎開始遞迴。 a 無法配對 q。引擎仍在遞迴中,嘗試第二個選項。 q 配對 q。引擎以成功的配對退出遞迴。引擎現在注意到量詞 {3} 已成功重複一次。它需要再重複兩次,因此引擎開始另一個遞迴。它再次配對 q。在量詞的第三次迭代中,第三次遞迴配對 q。最後,z 配對 z,找到整體配對。

這個正規表示式不配對 aqqz 或 aqqqqz。 aqqz 失敗,因為在量詞的第三次迭代中,遞迴無法配對 z。 aqqqqz 失敗,因為在 a(?R){3} 已配對 aqqq 之後,z 無法配對第四個 q。

正規表示式可以配對較長的字串,例如 aqaqqqzqz。對於這個字串,在量詞的第二次迭代中,遞迴配對 aqqqz。由於每個遞迴都分別追蹤量詞,因此遞迴需要連續三次遞迴才能滿足量詞的自身實例。這可能導致任意長的配對,例如 aaaqqaqqqzzaqqqzqzqaqqaaqqqzqqzzz。

Boost 如何處理遞迴中的量詞

Boost 對量詞在遞迴中的運作方式有自己的想法。遞迴僅在 Boost 中與其他版本中相同,如果遞迴運算子完全沒有量詞,或者如果它有 * 作為其量詞。任何其他量詞都可能導致 Boost 1.59 或更早版本與 Boost 1.60 及更高版本相較於其他正規表示式版本有非常不同的配對(或缺乏配對)。Boost 1.60 嘗試修復 Boost 和其他版本之間的一些差異,但它只導致不同的不相容行為。

在 Boost 1.59 及之前版本中,遞迴量詞會計算整個遞迴堆疊中的迭代和遞迴次數。因此,在 Boost 1.59 中,a(?R){3}z|q 的可能匹配項包括 aaaazzzz、aaaqzzz、aaqqzz、aaqzqz 和 aqaqzzz。在所有這些匹配項中,遞迴和迭代的次數加起來等於 3。其他版本不會找到這些匹配項,因為它們需要在每次遞迴期間進行 3 次迭代。因此,其他版本可以匹配類似 aaqqqzaqqqzaqqqzz 或 aqqaqqqzz 的字串。Boost 1.59 僅會在這些字串中匹配 aqqqz。

Boost 1.60 嘗試像其他版本一樣在每個遞迴層級迭代量詞,但執行方式不正確。任何使遞迴為可選的量詞都允許多次重複。因此,Boost 1.60 和更新版本會將 a(?R)?z 視為與 a(?R)*z 相同。雖然這修正了 a(?R)?z 在 Boost 1.59 中無法完全匹配 aaazzz 的問題,但它也允許其他版本無法使用此正規表示式找到的匹配項,例如 aazazz。如果量詞不是可選的,則 Boost 1.60 僅允許它在第一次遞迴期間匹配。因此,a(?R){3}z|q 只能匹配 q 或 aqqqz。

Boost 在遞迴量詞上的問題也會影響遞迴標記的父群組上的量詞。它們也會影響子常式呼叫上的量詞,以及包含子常式呼叫到具有量詞的群組的父群組的群組上的量詞。

遞迴中其他標記上的量詞

正規表示式中其他標記上的量詞在遞迴期間會正常運作。它們會在每次遞迴中分別追蹤其迭代。因此,a{2}(?R)z|q 會匹配 aaqz、aaaaqzz、aaaaaaqzzz 等。在每次遞迴期間,a 都必須匹配兩次。

像這樣位於遞迴中但不會重複遞迴本身的量詞在 Boost 中確實可以正確運作。

Quantifiers On Recursion
  • 简
  • 繁
  • En
About Regular Expressions » Regular Expressions Tutorial » Quantifiers On Recursion

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

Quantifiers On Recursion

The introduction to recursion shows how a(?R)?z matches aaazzz. The quantifier ? makes the preceding token optional. In other words, it repeats the token between zero or one times. In a(?R)?z the (?R) is made optional by the ? that follows it. You may wonder why the regex attempted the recursion three times, instead of once or not at all.

The reason is that upon recursion, the regex engine takes a fresh start in attempting the whole regex. All quantifiers and alternatives behave as if the matching process prior to the recursion had never happened at all, other than that the engine advanced through the string. The regex engine restores the states of all quantifiers and alternatives when it exits from a recursion, whether the recursion matched or failed. Basically, the matching process continues normally as if the recursion never happened, other than that the engine advanced through the string.

If you’re familiar with procedural programming languages, regex recursion is basically a recursive function call and the quantifiers are local variables in the function. Each recursion of the function gets its own set of local variables that don’t affect and aren’t affected by the same local variables in recursions higher up the stack. Quantifiers on recursion work this way in all flavors, except Boost.

Let’s see how a(?R){3}z|q behaves (Boost excepted). The simplest possible match is q, found by the second alternative in the regex.

The simplest match in which the first alternative matches is aqqqz. After a is matches, the regex engine begins a recursion. a fails to match q. Still inside the recursion, the engine attempts the second alternative. q matches q. The engine exits from the recursion with a successful match. The engine now notes that the quantifier {3} has successfully repeated once. It needs two more repetitions, so the engine begins another recursion. It again matches q. On the third iteration of the quantifier, the third recursion matches q. Finally, z matches z and an overall match is found.

This regex does not match aqqz or aqqqqz. aqqz fails because during the third iteration of the quantifier, the recursion fails to match z. aqqqqz fails because after a(?R){3} has matched aqqq, z fails to match the fourth q.

The regex can match longer strings such as aqaqqqzqz. With this string, during the second iteration of the quantifier, the recursion matches aqqqz. Since each recursion tracks the quantifier separately, the recursion needs three consecutive recursions of its own to satisfy its own instance of the quantifier. This can lead to arbitrarily long matches such as aaaqqaqqqzzaqqqzqzqaqqaaqqqzqqzzz.

How Boost Handles Quantifiers on Recursion

Boost has its own ideas about how quantifiers should work on recursion. Recursion only works the same in Boost as in other flavors if the recursion operator either has no quantifier at all or if it has * as its quantifier. Any other quantifier may lead to very different matches (or lack thereof) in Boost 1.59 or prior versus Boost 1.60 and later versus other regex flavors. Boost 1.60 attempted to fix some of the differences between Boost and other flavors but it only resulted in a different incompatible behavior.

In Boost 1.59 and prior, quantifiers on recursion count both iteration and recursion throughout the entire recursion stack. So possible matches for a(?R){3}z|q in Boost 1.59 include aaaazzzz, aaaqzzz, aaqqzz, aaqzqz, and aqaqzzz. In all these matches the number of recursions and iterations add up to 3. No other flavor would find these matches because they require 3 iterations during each recursion. So other flavors can match things like aaqqqzaqqqzaqqqzz or aqqaqqqzz. Boost 1.59 would match only aqqqz within these strings.

Boost 1.60 attempts to iterate quantifiers at each recursion level like other flavors, but does so incorrectly. Any quantifier that makes the recursion optional allows for infinite repetition. So Boost 1.60 and later treat a(?R)?z the same as a(?R)*z. While this fixes the problem that a(?R)?z could not match aaazzz entirely in Boost 1.59, it also allows matches such as aazazz that other flavors won’t find with this regex. If the quantifier is not optional, then Boost 1.60 only allows it to match during the first recursion. So a(?R){3}z|q could only ever match q or aqqqz.

Boost’s issues with quantifiers on recursion also affect quantifiers on parent groups of the recursion token. They also affect quantifiers on subroutine calls and quantifiers on groups that contain a subroutine call to a parent group of the group with the quantifier.

Quantifiers on Other Tokens in The Recursion

Quantifiers on other tokens in the regex behave normally during recursion. They track their iterations separately at each recursion. So a{2}(?R)z|q matches aaqz, aaaaqzz, aaaaaaqzzz, and so on. a has to match twice during each recursion.

Quantifiers like these that are inside the recursion but do not repeat the recursion itself do work correctly in Boost.

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