4.5.6 Possessive Quantifiers andAtomic Grouping
那么,仍然来考虑‘.625’的例子,想想我们真正的目的。我们知道,如果匹配能够进行到「(\.\d\d[1-9]?)▲\d+」中标记的位置,我们就不希望进行回溯。
那么,如果我们能够避免这些备用状态呢?(也就是在[1-9]进行尝试之前,放弃「?」保存的状态)如果没有退路,「1-9」的匹配就不会交还。而这就是我们需要的!
4.5.6.1 Atomic grouping with「(?>…)」
在固化分组匹配结束时,他已经匹配的文本已经固化为一个单元,只能作为整体而保留或放弃。
所以回溯永远也不能选择其中的状态(至少是,当此结构匹配完成时,“锁定(locked in)”在其中的状态)。
示例如下:
#! /usr/bin/perl -w
$price = 9.436;
#$price =~ s/(\.\d\d[1-9]?)\d+/$1/;
# $price =~ s/(\.\d\d[1-9]?)\d*/$1/;
# atomic grouping
$price =~ s/(\.\d\d(?>[1-9])?)/$1/;
print $1;
执行结果:
$perl mre45_32.pl
.436
加上「\d+」后,
执行结果:
$perl mre45_32.pl
Useof uninitialized value $1 inprint at mre45_32.pl line 10.
因为没有能够回溯的备用状态,整体匹配也就失败,‘.436’不需要处理,而这正是我们期望的。
固化分组会放弃某些可能的路径。
放弃备用状态可能会导致的结果:
l毫无影响 如果在使用备用状态之前能够完成匹配,固化分组就不会影响匹配。
l导致匹配失败
l改变匹配结果
l加快报告匹配失败的速度
4.5.7 Possessive Quantifiers, ?+, *+, ++, and {m, n}+
占有优先量词与匹配优先量词很相似,只是他们从来不交还已经匹配的字符。
实际上占有优先量词与固化分组的匹配结果完全一样,只是写起来更加方便而已(而且更加高效)。
修改后的示例:
#! /usr/bin/perl -w
$price = 9.436;
#$price =~ s/(\.\d\d[1-9]?)\d+/$1/;
# $price =~ s/(\.\d\d[1-9]?)\d*/$1/;
# atomic grouping
# $price =~ s/(\.\d\d(?>[1-9])?)d+/$1/;
# Possessive Quantifers
$price =~ s/(\.\d\d[1-9]?+)^\d+/$1/; # Prohibit Match
#price =~ s/(\.\d\d[1-9]?+)/$1/; # Match
print $1;
4.5.8 The Backtracking of Lookaround
在NFA的世界中包含了备用状态和回溯,环视是怎么实现的?
首先,我们要明白环视结构不会去包含备用状态和回溯!
包含了这两个的是子表达式!
然后,
那我们看,子表达式匹配成功时:
肯定型环视会认为自己匹配成功;而否定环视会认为匹配失败。在任何一种情况下,因为关注的只是匹配存在与否,此匹配尝试所在的“世界”(子表达式),包括在尝试中创造的所有备用状态,都会被放弃。
子表达式匹配失败时:
肯定型环视会认为自己匹配失败;而否定环视会认为匹配成功。
最后,我们知道环视、固化分组、占有优先量词他们是一样的!
4.5.8.1 Mimicking atomic grouping with positive lookahead
举例来说,比较「(?>\w+):」和「^(?=(\w+))\1:」
Unlike atomic grouping, the match word isnot included as part of the match (that’s the whole of lookahead), but the worddoes remain captured.
但与固化分组不一样的是,虽然此时确实捕获了这个单词,但是它不是全局匹配的一部分(这就是环视的意义)。
4.5.9 Is Alternation Greedy?
多选结构「…|…|…」既不是匹配优先的,也不是忽略优先的,而是按顺序排列的。
4.5.10 Taking Advantage of Ordered Alternation
要记住的是,如果多选分支是有序的,而能够匹配同样文本的多选分支又不只一个,就要小心安排多选分支的先后顺序。
4.5.10.1 Ordered alternation pitfalls
拆分日期的例子:
使用「Jan(0?[1-9]|[12][0-9]|3[01])」匹配‘Jan 31 is Dad’s birthday’,结果如何呢?我们希望获得的当然是‘Jan 31’,但是有序多选分支只会捕获‘Jan 3’。
所以我们用「Jan([12][0-9]|3[01]|0?[1-9])」可以解决这个问题。但是,看这个表达式很是不好理解~~