regulares - regexp javascript
Concordancia global de expresiones regulares en while() en el resultado de backtick (1)
La posición en la que //g
dejó está almacenada en magia añadida al escalar contra el que se realizó la coincidencia.
$ perl -MDevel::Peek -e''$_ = "abc"; Dump($_); /./g; Dump($_);''
SV = PV(0x32169a0) at 0x3253ee0
REFCNT = 1
FLAGS = (POK,IsCOW,pPOK)
PV = 0x323bae0 "abc"/0
CUR = 3
LEN = 10
COW_REFCNT = 1
SV = PVMG(0x326c040) at 0x3253ee0
REFCNT = 1
FLAGS = (SMG,POK,IsCOW,pPOK)
IV = 0
NV = 0
PV = 0x323bae0 "abc"/0
CUR = 3
LEN = 10
COW_REFCNT = 2
MAGIC = 0x323d050
MG_VIRTUAL = &PL_vtbl_mglob
MG_TYPE = PERL_MAGIC_regex_global(g)
MG_FLAGS = 0x40
BYTES
MG_LEN = 1
¡Esto significa que la única forma en que el comportamiento observado es posible en el ejemplo de retrocesos es si el operador de coincidencia coincide con el mismo escalar las cuatro veces que se evaluó! ¿Cómo es eso posible? Es porque backticks es uno de los operadores que usa un TARG.
¡Crear un escalar es relativamente costoso ya que requiere hasta tres asignaciones de memoria! Para aumentar el rendimiento, se asocia un escalar llamado TARG con cada instancia de algunos operadores. Cuando se evalúa a un operador con un TARG, puede llenar el TARG con el valor para devolver y devolver el TARG (en lugar de asignar y devolver uno nuevo).
"¿Y qué?", Podrías preguntar. Después de todo, ya has demostrado que la asignación a un escalar restablece la posición de coincidencia asociada con ese escalar. Eso es lo que se supone que debe suceder, pero no para los backticks.
Magic no solo permite que la información se adjunte a una variable, sino que también agrega funciones para ser llamadas bajo ciertas condiciones. La magia añadida por //g
une una función que debe invocarse después de que se modifica el escalar (que se indica mediante el indicador SMG
en el volcado anterior). Esta función es lo que despeja la posición cuando se asigna un valor al escalar.
El operador de asignación maneja la magia correctamente, pero no por el operador de retrocesos. No espera que se haya agregado magia a su TARG, por lo que no verifica si hay alguna, por lo que la función que borra la posición del partido no se llama.
Este script busca líneas con palabras y las imprime, mientras relee el archivo fuente en cada iteración :
# cat mm.pl
#!/usr/bin/perl
use strict;
use warnings;
while( `cat aa` =~ /(/w+)/g ) {
print "$1/n";
}
Fichero de entrada:
# cat aa
aa
bb
cc
Resultado:
# ./mm.pl
aa
bb
cc
Por favor, explícame por qué ejecutar el script no es infinito .
En todo momento, el desplazamiento de iteración para el motor de expresiones regulares debe reiniciarse porque la expresión se cambia (el nuevo gato se bifurca).
Pensé que Perl hace algún tipo de almacenamiento en caché para el resultado de gato , pero Strace afirma que el gato se generó 4 veces (3 por 3 líneas + 1 por condición falsa mientras estaba):
# strace -f ./mm.pl 2>&1 | grep cat | grep -v ENOENT
[pid 22604] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...>
[pid 22605] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...>
[pid 22606] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...>
[pid 22607] execve("/bin/cat", ["cat", "aa"], [/* 24 vars */] <unfinished ...>
Por otro lado, el siguiente ejemplo se ejecuta para siempre :
# cat kk.pl
#!/usr/bin/perl
use strict;
use warnings;
my $d = ''aaa'';
while( $d =~ /(/w+)/g ) {
print "$1/n";
$d = ''aaa'';
}
¿Dónde hay una diferencia entre los dos guiones? ¿Qué me estoy perdiendo?