Substituição de string com .subst em um loop for

8

Eu gostaria de fazer uma substituição de string em um forbloco usando uma captura nomeada. Eu esperava obter os números 1,2,3 como saída. Mas é Nilpara a primeira execução e, em seguida, 1 e 2 para a 2ª e a 3ª execução. Como uso .substcorretamente a construção do loop? Eu vejo o mesmo comportamento ao usar uma mapconstrução em vez do forloop. Funciona como esperado, se eu substituir por um valor fixo de string.

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
]
Valle Lukas
fonte
Estou curioso. O que é $ <nr>? (Não consegui encontrá-lo na documentação do raku.)
p6steve 28/01
2
@ p6steve chamada captura
Valle Lukas
docs.raku.org/language/… - obrigado @valle - encontrei-o agora!
p6steve 29/01
Talvez considere usar S///algumas vezes. Neste caso, você poderia fazerS[.$<nr>=(\d)] = $<nr> given $var
Jo King
@JoKing Nice. Votou seu comentário, depois desfiz o voto positivo, porque percebi que queria verificar uma coisa (o que acabou por não interessar), e agora o SO não me permitirá restabelecer meu voto positivo. Então, eu estou escrevendo isso para marcar manualmente sua sugestão com +1. Também o integrei na minha resposta.
raiph 30/01

Respostas:

9

DR; TL avaliação Defer de $<nr>até após a avaliação da expressão regular. @ JoKing ++ sugere uma maneira . Outra é apenas envolver a substituição com chaves ( {$<nr>}).

O que acontece quando o código original chama subst

Antes de Raku tentar chamar a substrotina, ele reúne uma lista de argumentos a serem transmitidos.

Existem dois valores. O primeiro é um regex. Ele não executar . O segundo valor é $<nr>. Ele avalia Nilporque, no início de um programa, a variável atual do objeto de correspondência está vinculada a algo que afirma que seu valor é Nile qualquer tentativa de acessar o valor de uma chave dentro dele - $<nr>- também retorna Nil. Então, as coisas já deram errado neste momento, antes substmesmo de correr.

Depois que Raku reúne essa lista de argumentos, ele tenta chamar subst. É bem-sucedido e substé executado.

Para obter a próxima partida, substexecute o regex. Isso atualiza a variável atual do objeto de correspondência $/. Mas é tarde demais para fazer alguma diferença no valor de substituição que já foi passado subst.

Com a partida na mão, a substseguir , olha o argumento de substituição. Ele encontra Nile age de acordo.

Para a segunda chamada de subst, $<nr>assumiu o valor da primeira chamada de subst. E assim por diante.

Duas maneiras de adiar a avaliação de $<nr>

@JoKing sugere considerar o uso de S///. Essa construção avalia primeiro o regex (entre o primeiro par de /s) e depois a substituição (entre o último par de /s). (O mesmo princípio se aplica se você usar outras Ssintaxes válidas, como S[...] = ....)

Se você usar subst, então, como explicado na seção anterior, Raku reúne a lista de argumentos antes de chamá-lo. Ele encontra uma regex (que não é executada) e um fechamento (que também não é executado). Em seguida, tenta ligar substcom esses argumentos e consegue fazê-lo.

Em seguida, substcomeça a correr. Ele recebeu código para a partida (uma regex) e a substituição (um fechamento).

Ele executa a regex como a operação correspondente. Se o regex retornar uma correspondência, ele substexecutará o fechamento e usará o valor que ele retornará como substituição.

Assim, como passamos de passar $<nr>como um valor nu, o que significava que ele estava congelado Nil, para passá-lo embrulhado em um fechamento, que adiou sua avaliação até $/que fosse definido como uma correspondência com uma <nr>entrada preenchida , resolvemos o problema.

Observe que isso só funciona porque quem projetou / implementou substfoi inteligente / agradável o suficiente para permitir que os argumentos de correspondência e substituição sejam formas de Code(uma regex para a correspondência e fechamento comum para a substituição) se um usuário desejar. Em seguida, ele executa a partida primeiro e só então executa o fechamento da substituição se tiver sido aprovada uma, usando o resultado dessa última chamada como a substituição final. Da mesma forma, S///funciona porque que foi concebido apenas para avaliar a substituição após ser avaliadas primeiro a substituição.

raiph
fonte