Reemplazo de cadena con .subst en un bucle for

8

Me gustaría hacer una sustitución de cadena en un forbloque usando una captura con nombre. Esperaba obtener los números 1,2,3 como salida. Pero es Nilpara la primera carrera, y luego 1 y 2 para la segunda y tercera carrera. ¿Cómo uso .substcorrectamente en la construcción de bucle? Veo el mismo comportamiento cuando uso una mapconstrucción en lugar del forbucle. Funciona como se esperaba, si lo reemplazo con un valor de cadena fijo.

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
fuente
Tengo curiosidad ¿Qué es $ <nr>? (No pude encontrarlo en la documentación de raku.)
p6steve
2
@ p6steve llamado captura
Valle Lukas
docs.raku.org/language/… - gracias @valle - ¡lo encontré ahora!
p6steve
Quizás considere usar a S///veces. En este caso, podrías hacerloS[.$<nr>=(\d)] = $<nr> given $var
Jo King
@JoKing Nice. Voté su comentario, luego desestimé el voto porque me di cuenta de que quería verificar algo (que resultó no importar), y ahora SO no me permite restablecer mi voto. Así que escribo esto para hacer +1 manualmente en su sugerencia agradable. También lo he integrado en mi respuesta.
Raiph

Respuestas:

9

TL; DR Aplazar la evaluación $<nr>hasta después de la evaluación de la expresión regular. @ JoKing ++ sugiere una forma . Otra es simplemente envolver el reemplazo con llaves ( {$<nr>}).

¿Qué sucede cuando su código original llama? subst

Antes de que Raku intente llamar a la substrutina, reúne una lista de argumentos para pasarle.

Hay dos valores El primero es una expresión regular. No , no funciona . El segundo valor es $<nr>. Se evalúa Nilporque, al comienzo de un programa, la variable de objeto de coincidencia actual está vinculada a algo que afirma que su valor es Nily cualquier intento de acceder al valor de una clave dentro de él $<nr>- también devuelve Nil. Entonces, las cosas ya han salido mal en este punto, antes de substque se ejecute.

Una vez que Raku ha reunido esta lista de argumentos, intenta llamar subst. Tiene éxito y substcorre.

Para obtener el próximo partido, substejecuta la expresión regular. Esto actualiza la variable de objeto de coincidencia actual $/. Pero es demasiado tarde para hacer alguna diferencia en el valor de sustitución al que ya se ha pasado subst.

Con una coincidencia en la mano, substluego mira el argumento de sustitución. Lo encuentra Nily actúa en consecuencia.

Para la segunda llamada de subst, $<nr>ha tomado el valor de la primera llamada de subst. Y así.

Dos formas de diferir la evaluación de $<nr>

@JoKing sugiere considerar el uso de S///. Esta construcción evalúa primero la expresión regular (entre el primer par de /s), luego el reemplazo (entre el último par de /s). (El mismo principio se aplica si utiliza otras Ssintaxis válidas como S[...] = ...).

Si usa subst, entonces, como se explicó en la sección anterior, Raku reúne la lista de argumentos antes de llamarlo. Encuentra una expresión regular (que no se ejecuta) y un cierre (que tampoco se ejecuta). Luego intenta llamar substcon esos argumentos y logra hacerlo.

A continuación, substcomienza a correr. Ha recibido código tanto para el partido (una expresión regular) como para la sustitución (un cierre).

Ejecuta la expresión regular como la operación de coincidencia. Si la expresión regular devuelve una coincidencia, substejecuta el cierre y utiliza el valor que devuelve como la sustitución.

Por lo tanto, debido a que cambiamos de pasar $<nr>como un valor desnudo, lo que significaba que se congelaba Nil, a pasarlo envuelto en un cierre, lo que aplazó su evaluación hasta que $/se ajustara a una coincidencia con una <nr>entrada poblada , resolvimos el problema.

Tenga en cuenta que esto solo funciona porque quien diseñó / implementó substfue lo suficientemente inteligente / amable como para permitir que los argumentos de coincidencia y sustitución sean formas de Code(una expresión regular para la coincidencia y el cierre ordinario para la sustitución) si un usuario lo desea. Luego ejecuta el partido primero y solo luego ejecuta el cierre de sustitución si se ha pasado uno, utilizando el resultado de esa última llamada como la sustitución final. Del mismo modo, S///funciona porque eso ha sido diseñado para evaluar solo el reemplazo después de que primero se evaluó la sustitución.

raiph
fuente