Raku正则表达式:如何在反向预查中使用捕获组

8

我如何在回顾断言中使用捕获组?

我尝试使用与这个答案相同的公式。但这似乎在回顾断言中无法工作。

从概念上讲,这就是我试图做的事情。

say "133" ~~ m/ <?after $0+> (\d) $ /

我知道这可以很容易地实现,没有使用回顾后发表达式,但现在先忽略这一点 :)

为此,我尝试了以下选项:

使用 :var 语法:

say "133" ~~ m/ <?after $look-behind+> (\d):my $look-behind; $ /;
# Variable '$look-behind' is not declared

使用代码块语法,在外部定义变量:

my $look-behind;
say "133" ~~ m/ <?after $look-behind+> (\d) {$look-behind=$0} $ /;
# False

似乎问题出在lookbehind 在执行 "code block/:my $var" 之前,因此变量对于固定后面的内容没有值。
是否有办法在 lookbehind 中使用捕获组?

一个好奇心:say .<after> given foo ~~ m/ $ <after bar> / 对于以模式 bar 结尾的 foo 中的任何字符串都有效,这是公平的...并显示一个捕获,该捕获是 foo 中的字符串整个(不仅仅是 bar)并且完全翻转(倒序)! - raiph
我知道这可以很容易地实现,而不需要使用lookbehinds,但现在暂且忽略它 :) 我已经忽略了一天,但现在是新的一天。 :) 那么,你真正想做什么? - raiph
Raku中的正则表达式是代码。您不会期望在设置变量之前它已经包含数据,那么为什么您会对正则表达式有同样的期望呢? - Brad Gilbert
1
嗨@raiph,我尝试使用正则表达式(以及其中的内联代码)解决了Advent of Code的第15天。最终我反转了输入数字并使用了前瞻而不是后顾。但是,我想知道是否存在一种使用raku在后顾中引用捕获组的方法,所以我问了一下... :) - Julio
@BradGilbert 嗯,我并没有期望什么 xD,那只是我为了试一试而尝试的东西... - Julio
1
@Julio 谢谢。我在发表评论后明白了你的问题。如果你还没有弄清楚,使用jnthn关于lookahead/ (a) :my $lookahead; <?before b {$lookahead = $/}> /)的答案,将其简单转换为解决此Q的lookbehind版本将是 / (a) :my $lookbehind; { $lookbehind = $/ } <?after $lookbehind ** 2> $ /;。(这与.@WiktorStribiżew的答案差不多。) - raiph
1个回答

8
当你在实际捕获之前引用一个已捕获的值时,它没有被初始化,因此你无法匹配。你需要在实际使用回溯到捕获的值之前定义捕获组。
接下来,你需要定义一个代码块,并将回溯到的值分配给一个变量,以便在整个正则表达式模式中使用,否则,在向后查找模式中无法看到它。请参见这个 Capturing Raku reference

这个代码块发布了正则表达式内的捕获,以便可以将其分配给其他变量或用于后续匹配。

你可以使用类似以下的内容:
say "133" ~~ m/ (\d) {} :my $c=$0; <?after $c ** 2> $ /;

这里,(\d)匹配并捕获数字,然后使用代码块将此捕获的值分配给变量$c,然后<?after $c ** 2>向后查找检查$c值是否至少出现两次在当前位置左侧,然后$锚点检查当前位置是否为字符串结尾。
请参见此在线Raku演示

1
太棒了!这是一个很好的技巧,可以推迟回溯并再次读取其中捕获的组! - Julio
值得指出的是,需要使用{}的原因是为了更新$/。($0实际上是$/[0]的快捷方式) - Brad Gilbert

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