Raku正则表达式: 如何在lookahead中使用捕获组

8

我应该如何在预查表达式中使用捕获组?

这段代码:

say "ab" ~~ m/(a) <?before (b) > /;

返回值:

「a」
 0 => 「a」

但是我希望也能捕获 'b'。

有没有办法做到这一点?

我不想让'b'被排除在lookahead之外,因为我不想让'b'成为匹配的一部分。

有没有办法捕获 'b',但仍然让它保持在匹配之外?

注意:

我试图使用Raku的 capture markers,如下所示:

say "ab" ~~ m/<((a))> (b) /;

「a」
 0 => 「a」
 1 => 「b」

但是实际上这似乎没有按照我预期的工作,因为即使'b'未被匹配成功,正则表达式也已经处理过了它。而我不希望被处理。
例如:
say 'abab' ~~ m:g/(a)<?before b>|b/;

(「a」
    0 => 「a」
 「b」 
 「a」
    0 => 「a」
 「b」)

# Four matches (what I want)
 

say 'abab' ~~ m:g/<((a))>b|b/;

(「a」
    0 => 「a」 
 「a」
    0 => 「a」)

# Two matches

有没有一种方法可以捕获 'b' 但仍将其保留在匹配之外?-- 您似乎提出的基本问题是是否可以在不进行匹配的情况下进行捕获。据我所知,Raku(以及Perl)的正则表达式系统旨在匹配和可选捕获,而不是相反。但是请参见Jonathan的答案以获取高级编码。 - jubilatious1
对于在家阅读的读者来说,更常见的是使用不嵌套的捕获标记<()>,例如<(a)>而不是<((a))>,请参见:https://docs.raku.org/language/regexes#Capture_markers:_%3C(_)%3E)。 - jubilatious1
使用最新的 Rakudo_2020.10(从源代码构建),我在朱利奥的第三个代码块示例中看到了不同的结果,可以参见:https://gist.github.com/jubilatious1/e4da45c3020f3c8c745c2c4325e33c6f。 - jubilatious1
1
@jubilatious1 我相信结果是一样的。我得到了和你一样的结果,只是在元素之间添加了一些换行符,在显示每个组的内容后添加了一个新行。我相信应该是这样的,但由于某种原因,下一行被附加到前一行上。 - Julio
谢谢留言!是的,Raku似乎输出了一种“紧凑”的匹配形式,我想知道是否有一种自动展开它的例程? - jubilatious1
1个回答

7
有没有一种方法可以这样做? 其实不是很可能,但有点类似。有三个因素阻碍我们实现它。
1. Raku正则表达式捕获匹配的树形结构。因此,(a(b))会产生一个包含另一个位置捕获的位置捕获。我为什么要提到这个?因为对于像before这样以正则表达式作为参数的东西也是一样的:传递给before的正则表达式会得到自己的Match对象。 2. 符号?意味着“不捕获”。我们可能想要去掉它,得到,确实现在Match对象中有一个before关键字,听起来很有前途,但是… 3. before实际上并不返回内部匹配的内容,而是返回一个零宽度的Match对象,否则如果我们忘记了?,就会得到一个非向前查看。
如果我们只能从前瞻中救出Match对象就好了。那么,我们可以声明一个变量,并将before参数正则表达式中的$/绑定到其中:
say "ab" ~~ m/(a) :my $lookahead; <?before b {$lookahead = $/}> /;
say $lookahead;

这将得到:

「a」
 0 => 「a」
「b」

这种方法是可行的,但不幸的是它不能像正常捕获一样被附加。虽然没有办法实现这个,但我们可以通过 make 来附加它:

say "ab" ~~ m/(a) :my $lookahead; <?before (b) {$lookahead = $0}> { make $lookahead } /;
say $/.made;

使用相同的输出,除了现在它将可靠地附加到从m:g返回的每个匹配对象上,因此即使不美观也将更加健壮。


"ab" ~~ m/(a) <?before (b) {$¢.make: $0}> / 在最近的Rakudo中可以工作。 - raiph
@raiph 嗯,我有点惊讶……指的是什么? - Jonathan Worthington
这是我找到的唯一一个烤测试。注意,我还没有在 roast 中进行 grep(目前没有桌面)。S05 从这里开始有12个匹配项。 - raiph
@jnthn 我理解的是 主要是为了区分 CursorMatch,而这主要涉及到 Raku 的高级功能和性能,例如与解析状态相关的只读和读写能力,以及 $0 等的更新/发布,最终 @Larry 决定清空 Match 的超类型 Cursor,使得 成为一个退化的、几乎可以不用的东西。 - raiph
更多注释。来自SO答案:"[是]最近的最外层匹配"。有关文档讨论,请参见Match页面 - raiph
1
@raiph 我认为其中一个重要问题应该是当 $¢ 获得新的作用域时。在语法中,每个标记基本上都有自己的 ,因此问题是传递为参数的正则表达式(就像 <before…> 中实际发生的那样)是否应该引用主要的 (在这种情况下 $¢.make 应该有效),还是它应该获得自己的作用域(因此 $¢.make 就像非捕获匹配中的 $/.make 一样有用)。说实话,我倾向于认为后者是正确的行为,但它肯定属于潜在的歧义/陷阱领域。 - user0721090601

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