au3 正则参考 -37-贪婪与惰性限定符
<!DOCTYPE html>
贪婪限定符与惰性限定符
限定符有两种版本:
• 贪婪版本. 贪婪限定符尝试尽可能多地匹配元素.
• 非贪婪(惰性) 版本. 贪婪限定符尝试尽可能少地匹配元素. 只需添加 ? 便可以将贪婪限定符转换为惰性限定符.
举例一个简单的正则表达式, 旨在从信用卡号之类的数字串中提取最后四位数. 使用 贪婪限定符的正则表达式版本为 \b.([0-9]{4})\b.
但如果输入字符串包含两组数字, 则此正则表达式只与第二组数字的最后四位数匹配:
字符串: 1112223333 3992991999
表达式: \b.([0-9]{4})\b
匹配结果(标志 3): [0]1999
该正则表达式未能匹配第一个卡号, 因为 限定符尝试在整个字符串中尽可能多地匹配前面的元素, 因此它在字符串的末尾找到了匹配项.
可以使用 ? 惰性限定符从两组号码提取数字, 如下面的示例匹配的数字:
字符串: 同上例.
表达式: \b.?([0-9]{4})\b
匹配结果(标志 3): [0]3333 [1]1999
在大多数情况下, 带有贪婪限定符和惰性限定符的正则表达式将返回相同的匹配项. 在与元字符 . (匹配任何字符)一起使用时, 它们多数情况下会返回不同的结果.
限定符和空匹配
限定符 , +,和 {n,m} 以及它们的贪婪限定符在找到最小捕获数后遇到空匹配则不再重复. 此规则会阻止限定符在可能的组捕获最大数目为无限大或接近无限大时进入空子表达式匹配的无限循环.
例如下面示例调用正则表达式模式 (a?) 的结果, 将匹配零个或一个 a 字符零次或多次. 请注意, 单个捕获组捕获每个 a 以及空匹配, 但没有第二个空匹配, 因为第一个空匹配导致限定翻译停止重复.
字符串: aaabbb
表达式: (a?)
匹配结果(标志 2): [0]aaa
要查看定义最小和最大捕获数与定义固定捕获数的捕获组之间的实际差异, 请考虑正则表达式模式 (a\1|(?(1)\1)){0,2} 和 (a\1|(?(1)\1)){2}. 这两个正则表达式都包含一个捕获组, 如下表中所定义:
模式 | 说明 |
---|---|
(a\1 | 随着第一次捕获组的值匹配 a …… |
(?(1) | … 或测试是否已定义第一个捕获组. (请注意, (?(1) 构造不定义捕获组.) |
\1)) | 如果第一个捕获分组存在, 则与其值相匹配; 如果分组不存在, 则分组将与 空字符相匹配. |
表达式 (a\1|(?(1)\1)){0,2} 试图匹配此模式 0 至 2 次, 而表达式 (a\1|(?(1)\1)){2} 则确定为 2 次. 由于第一个模式在第一次捕获空匹配时达到其最小捕获量, 因此它绝不会重复尝试匹配 a\1; {0,2} 限定符只允许在最后的迭代中存在空匹配. 与之相反, 第二个常规表达式 (a\1|(?(1)\1)){2} 与 a 匹配, 因为它会再一次计算 a\1; 最小迭代次数为 2, 可强制引擎在空匹配后重复.
匹配次数的贪婪与非贪婪
在使用限定符时, 有几种表示方法可以使同一个表达式能够匹配不同的次数, 具体匹配的次数随被匹配的字符串而定.
这种重复匹配不定次数的表达式在匹配过程中, 总是尽可能多的匹配.
贪婪模式:
贪婪限定符: {m,n}, {m,}, ?, , +. 贪婪限定符首先尝试匹配最大数量的重复.
针对文本 dxxxdxxxd 举例如下:
表达式: (d)(\w+)
匹配结果(标志 2):
[0]dxxxdxxxd
[1]d
[2]xxxdxxxd
表达式分析:
模式 | 说明 |
---|---|
(d) | 捕获组 1 . 匹配文本开头字符 d |
(\w+) | 捕获组 2 . \w+ 将匹配第一个 d 之后的所有字符 xxxdxxxd . |
表达式: (d)(\w+)(d)
匹配结果(标志 2):
[0]dxxxdxxxd
[1]d
[2]xxxdxxx
[3]d
表达式分析:
模式 | 说明 |
---|---|
(d) | 捕获组 1 . 匹配文本开头字符 d . |
(\w+) | 捕获组 2 . \w+ 将匹配第一个和最后一个 d 之间的所有字符. 虽然 \w+ 也能够匹配最后一个 d , 但是为了使整个表达式匹配成功, \w+ 可以 "让出" 它本来能够匹配的最后一个 d . |
(d) | 捕获组 3 . 匹配文本最后字符 d . |
由此可见, \w+ 在匹配的时候, 总是尽可能多的匹配符合它规则的字符. 虽然第二个举例中, 它没有匹配最后一个 d , 但那也是为了让整个表达式能够匹配成功.
同理, 带 和 {m,n} 的表达式都是尽可能地多匹配, 带 ? 的表达式在可匹配可不匹配的时候, 也是尽可能的 "要匹配". 这种匹配原则就叫作贪婪模式.
非贪婪模式:
懒惰限定符: ??, ?, +?, {n,m}? . 这些限定符指示回溯引擎首先搜索最少数量的重复.
在限定符后再加上一个 ? 号, 则可以使匹配次数不定的表达式尽可能少的匹配, 使可匹配可不匹配的表达式, 尽可能的 "不匹配".
这种匹配原则叫作非贪婪模式, 也叫作 "勉强" 模式. 如果少匹配就会导致整个表达式匹配失败的时候, 与贪婪模式类似, 非贪婪模式会最小限度的再匹配一些, 以使整个表达式匹配成功.
针对文本 dxxxdxxxd 举例如下:
表达式: (d)(\w+?)
匹配结果(标志 2):
[0]dx
[1]d
[2]x
表达式分析:
模式 | 说明 |
---|---|
(d) | 捕获组 1 . 匹配文本开头字符 d . |
(\w+?) | 捕获组 2 . 将尽可能少的匹配第一个 d 之后的字符, 结果 \w+? 只匹配了一个 x . |
表达式: (d)(\w+?)(d)
匹配结果(标志 2):
[0]dxxxd
[1]d
[2]xxx
[3]d
表达式分析:
模式 | 说明 |
---|---|
(d) | 捕获组 1 . 匹配文本开头字符 d . |
(\w+?) | 捕获组 2. \w+? 不得不只匹配 "xxx" 才可以让后边的 d 匹配, 从而使整个表达式匹配成功. 因此结果是: \w+? 匹配 xxx . |
(d) | 捕获组 3 . 匹配文本最后字符 d . |
正则表达式 .+(\d+). 包含贪婪限定符 .+ , 这使正则表达式引擎仅捕获该数字的最后一位数.
相比之下, 正则表达式 .+?(\d+). 包含惰性限定符 .+? , 这使正则表达式引擎捕获整个数字.
用以上两个表达式分别测试字符串: This sentence ends with the number 107325.
贪婪模式 .+(\d+). 匹配数字 5. 因为任意字符 . 的贪婪模式, 数字 5 前面的所有字符已被 .+ 捕获, 所有 \d+ 只能匹配剩下的数字字符 5.
惰性模式 .+?(\d+). 匹配整个数字 107325.
此正则表达式的贪婪版本和惰性版本的模式定义如下表所示:
模式 | 说明 |
---|---|
.+ | 贪婪模式. 匹配任意字符的至少一个匹配项, 无上限. 这会使正则表达式引擎先匹配整个字符串, 然后根据需要进行回溯以匹配模式的其余部分. |
.+? | 惰性模式. 匹配任意字符的至少一个匹配项(尽可能少地匹配). |
(\d+) | 匹配在句点前面的至少一个数字字符, 无上限. 并将其分配给第一个捕获组. |
. | 匹配句点. |
发表评论
木有头像就木JJ啦!还木有头像吗?点这里申请属于你的个性Gravatar头像吧!