Perl正则表达式:"??"的含义是什么?

4

我在我的脚本中有一个正则表达式,我写了好几年了。

我知道这个正则表达式的作用(查找大于80%的百分比),但我不记得它的含义/原理。我看到使用了三元运算符,还有最后一个闭合括号匹配,但是我不知道例如 ?? 的含义:

qr/^(\d+)%$(??{$^N>= 80 ? '':'^'})/

有人能为我解释一下这个正则表达式吗?


4
这是一个关于 Perl 正则表达式的文档页面,其中介绍了一种特殊语法 (??{code}),它允许在正则表达式中嵌入代码。当匹配到该语法时,Perl 会执行其中的代码并将其结果作为匹配结果返回。 - melpomene
3
顺便说一下,那是一个相当棘手的特性。为什么不这样写:if ( (/^([0-9]+)\s*%/)[0] > 80 ) ... - zdim
@zdim 不错。我不记得为什么要使用嵌入式代码了。我也会尝试你的解决方案。 - taiko
2个回答

9
在我回答之前,我要指出如果你不完全理解嵌入式perl代码形式(??...)的含义,使用它可能会充满错误。我写了20多年的perl正则表达式,我的自然倾向是将这样的“用例”编码为正则表达式结果的过滤器,而不是直接嵌入perl代码。警示! 好的,让我们分析一下这个正则表达式:
^           # start of text

(           # begin capture group
  \d+         # one or more digits 0-9
)           # end of capture group

%           # literal percent sign character

$           # end of text

(??{        # start embedded perl code

  $^N >= 80   # if last closed match group($^N) is greater than or equal to 80
    ? ''        # then return empty pattern ('') 
    : '^'       # else return start of text (^) pattern

})          # end embedded perl code

$^N 引用最近匹配成功的子字符串,(??{ ... }) 零宽断言会执行包含在其中的Perl代码,并将返回值转换为新的正则表达式,这个新的正则表达式将被添加到原始模式中。

因此,在这个例子中,我们匹配一个或多个数字并紧接着一个百分号字符。然后,如果捕获的值大于或等于80,则对文本执行一个空模式(实际上允许整个模式匹配并返回捕获的值),否则,执行 ^(开始)模式,该模式不能匹配字符串末尾,从而不返回任何内容。

注意,通过在Perl正则表达式中添加/x修饰符,您可以直接将注释嵌入到模式中,同时忽略嵌入的空格。我发现这是记录复杂正则表达式的好方法。)


3
需要注意的是,捕获组将匹配大于100%的值,这可能不是预期的结果。将捕获组更改为“100 | \ d {1,2}”以匹配从0到100的值。 - Rob Raisch
非常好的观点。然而,在这种情况下,值不能大于100%,因为我们正在谈论磁盘使用率。 - taiko
1
当然可以,但你想要理解的正则表达式将允许大于100的值。 - Rob Raisch

6

$(??{代码})执行代码,然后将结果替换到正则表达式中。其中,$^N会被替换成最近捕获组匹配的内容,此处为(\d+)。带有此替换的正则表达式再次进行匹配。

因此,如果字符串以一个数字和%开头,^(\d+)%会匹配它。然后执行$^N >= 80 ? '' : '^',用数字替换$^N。如果数字至少是80,则正则表达式变为^(\d+)%,整个匹配成功。但如果数字小于80,则变为^(\d+)%^。由于第二个^不能在字符串中间匹配,正则表达式不再匹配。

因此,这个正则表达式匹配以百分数至少为80开头的字符串。


太棒了,非常感谢你。如果你将来写一本关于编程的书,请记得签我进去。我会提前预订的 :) - taiko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接