我想使用命名捕获在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
]
答案 0 :(得分:9)
TL; DR 将对$<nr>
的评估推迟到对正则表达式进行评估之后。 @ JoKing ++建议使用one way。另一个方法是只用大括号({$<nr>}
)包装替换项。
subst
在Raku尝试调用subst
例程之前,它会汇总一组要传递给它的参数。
有两个值。第一个是正则表达式。 它不运行。第二个值是$<nr>
。它求值为Nil
,因为在程序开始时,当前的match对象变量绑定到某个声明其值为Nil
的对象,并且尝试访问其中的键值- $<nr>
-还返回Nil
。因此,在subst
运行之前,这一点已经出错了。
一旦Raku汇编了此参数列表,它将尝试调用subst
。成功,subst
运行。
要获得下一个匹配项,subst
运行正则表达式。这将更新当前的匹配对象变量$/
。但是为时已晚,现在已经与已经传递给subst
的替换值没有任何区别。
有了匹配项,subst
接下来将查看替换参数。它发现它是Nil
并采取相应措施。
对于subst
的第二调用,$<nr>
接受了subst
的第一调用中的值。依此类推。
$<nr>
进行评估的两种方法 @JoKing建议考虑使用S///
。此构造首先评估正则表达式(在第一对/
之间),然后评估替换(在最后一对/
之间)。 (如果您使用其他有效的S
语法,例如S[...] = ...
,则适用相同的原理。)
如果使用subst
,则如前一节所述,Raku在调用它之前将其参数列表放在一起。它找到一个正则表达式(它不运行)和一个闭包(它也不运行)。然后,它尝试使用这些参数调用subst
并成功执行此操作。
接下来,subst
开始运行。它已经收到了 match (一个正则表达式)和 substitution (一个闭包)的代码。
它运行正则表达式作为匹配操作。如果正则表达式返回匹配项,则subst
运行闭包并使用它返回的值作为替换。
因此,因为我们从将$<nr>
传递为裸值(这意味着将其冻结为Nil
)切换为将其包装在闭包中,从而将其评估推迟到$/
设置为具有填充的<nr>
条目的匹配项,我们解决了该问题。
请注意,这仅是因为设计/实现subst
的人足够聪明/好,足以使匹配的和替代参数都采用Code
的形式(正则表达式(如果是匹配项,则用普通的闭包代替))。然后,它首先运行 match ,只有 then 才运行替换闭包(如果已通过替换闭包),并使用后一个调用的 result 作为最后一个替代。同样,S///
之所以有效,是因为那个被设计为仅在首次评估替换后评估替换。