在 for 循环中用 .subst 替换字符串

String replacement with .subst in a for loop

我想使用命名捕获在 for 块中进行字符串替换。我期望得到数字 1,2,3 作为输出。但是第一个运行是Nil,第二个和第三个运行是1和2。如何在循环结构中正确使用 .subst?当使用 map 构造而不是 for 循环时,我看到了相同的行为。如果我用固定字符串值替换,它确实按预期工作。

for <a1 b2 c3> -> $var {
    say $var;
    say $var.subst(/.$<nr>=(\d)/, $<nr>); #.subst(/.$<nr>=(\d)/, 'X'); #OK      
}

#`[
This is Rakudo version 2019.11 built on MoarVM version 2019.11   
Output:

a1
Use of Nil in string context
  in block  at test3.pl6 line 3

b2
1
c3
2
]

TL;DR$<nr> 的计算推迟到正则表达式的计算之后。 @JoKing++ 建议 。另一种方法是用大括号 ({$<nr>}).

包裹替换

当您的原始代码调用 subst

时会发生什么

在 Raku 尝试调用 subst 例程之前,它会将要传递给它的参数列表放在一起。

有两个值。第一个是正则表达式。 不是运行。第二个值为 $<nr>。它的计算结果为 Nil,因为在程序开始时,当前匹配对象变量绑定到声称其值为 Nil 的对象,并且任何试图访问其中键值的尝试—— $<nr> -- 也 returns Nil。所以在 subst 曾经 运行s.

之前,事情已经出了问题

一旦 Raku 收集了这个参数列表,它就会尝试调用 subst。它成功了,并且 subst 运行s.

要获得下一个匹配项,subst 运行 正则表达式。这将更新当前匹配对象变量 $/。但是要对已经传递给 subst.

的替代值产生任何影响已经太迟了

有了匹配项,subst 接下来查看替换参数。它发现它是 Nil 并据此采取行动。

对于 substsecond 调用,$<nr> 已采用 first 调用的值subst 个。等等。

延迟计算 $<nr>

的两种方法

@JoKing 建议考虑使用 S///。此构造首先评估正则表达式(在第一对 / 之间),然后是替换(在最后一对 / 之间)。 (如果您使用其他有效的 S 语法,如 S[...] = ...,同样的原则也适用。)

如果你使用subst,那么,如前一节所述,Raku 在调用它之前将参数列表放在一起。它找到一个正则表达式(它没有 运行)和一个闭包(它也没有 运行)。然后它尝试使用这些参数调用 subst 并成功调用。

接下来,subst 开始 运行ning。它已收到 match(正则表达式)和 substitution(闭包)的代码。

它运行将正则表达式作为匹配操作。如果正则表达式 returns 匹配,则 subst 运行 关闭并使用它的值 returns 作为替换。

因此,因为我们从将 $<nr> 作为裸值传递(这意味着它被冻结为 Nil)切换到将其包裹在闭包中传递,这将其评估推迟到 [=23] =] 已设置为与填充的 <nr> 条目匹配,我们解决了问题。

请注意,这只有效,因为 designed/implemented subst smart/nice 足以让匹配 替换参数成为形式Code(用于匹配的正则表达式和用于替换的普通闭包)如果用户需要的话。然后 运行 首先 匹配 然后 运行 替换闭包,如果它已经通过了一个,使用后一个调用的 result 作为最终替换。类似地,S/// 有效,因为 that 被设计为仅在首次评估替换后才评估替换。