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

Val*_*kas 9 string-substitution raku

我想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
]
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 10

TL;DR推迟评估$<nr>直到评估正则表达式之后。@JoKing++ 建议一种方式。另一种方法是用大括号 ( {$<nr>})包裹替换。

当您的原始代码调用时会发生什么 subst

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

有两个值。第一个是正则表达式。它并没有运行。第二个值是$<nr>。它的计算结果为 ,Nil因为在程序开始时,当前匹配对象变量绑定到声称其值为 is 的东西,Nil并且任何试图访问其中的键值的尝试 - $<nr>- 也会返回Nil。所以在这一点上,在subst运行之前,事情已经出错了。

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

要获得下一场比赛,请subst运行正则表达式。这会更新当前的匹配对象变量$/。但是现在对已经传递给 的替换值产生任何影响已经太晚了subst

有了 match,subst接下来看看替换参数。它发现它Nil并相应地采取行动。

对于 的第二次调用subst$<nr>已采用 的第一次调用的值subst。等等。

延迟评估的两种方式 $<nr>

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

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

接下来,subst开始运行。它已收到匹配(正则表达式)和替换(闭包)的代码。

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

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

请注意,这仅有效,因为设计/实现的subst人足够聪明/足够好,允许匹配替换参数都是Code(匹配的正则表达式和替换的普通闭包)的形式,如果用户想要的话。然后它首先运行匹配然后才运行替换闭包,如果它被传递了一个,使用后一个调用的结果作为最终替换。同样,S///之所以有效是因为被设计为仅在第一次评估替换之后才评估替换。