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

时间:2020-01-22 19:47:00

标签: raku string-substitution

我想使用命名捕获在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
]

1 个答案:

答案 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///之所以有效,是因为那个被设计为仅在首次评估替换后评估替换。