Página 1 de 1

Duda con contexto arreglo

NotaPublicado: 2017-12-14 17:36 @775
por MARKO
Hola de nuevo, Perl en español. Quisiera saber qué diferencia tiene direccionar algo hacia una variable escalar entre paréntesis y direccionar ese mismo algo hacia un arreglo.

Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
  1. #!/usr/bin/perl
  2.  
  3. my $nombre;
  4. my @nombres;
  5.  
  6. my $fichero = "fichero.rar datos.rar cosas.rar";
  7.  
  8. ($nombre) = $fichero =~ /^(.+)\.rar$/i;
  9. @nombres = $fichero =~ /^(.+)\.rar$/i;
  10.  
  11.  
Coloreado en 0.003 segundos, usando GeSHi 1.0.8.4

¿Diferencias entre ($nombre) y @nombres?

¿¿Por qué usar uno en vez del otro??

Gracias por adelantado.

Re: Duda con contexto arreglo

NotaPublicado: 2017-12-14 19:01 @834
por explorer
Hay funciones en Perl que se comportan de forma distinta según se estén ejecutando en contexto escalar o de lista. Es el caso de las expresiones regulares.

Si una expresión regular la ejecutamos en contexto escalar, nos devolverá verdadero o falso según el resultado de la búsqueda o coincidencia con el patrón. Por eso podemos usar expresiones regulares en while() e if() y en otros sitios donde sólo nos interesa saber si hay coincidencia con el patrón o no.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
if ( $fichero =~ /^.+?[.]rar$/i ) {
    say "$fichero es un archivo RAR";
}
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

En cambio, si una expresión regular la ejecutamos en contexto de lista, nos devolverá una lista (obviamente) de todos los subpatrones capturados por los paréntesis. Si no es capaz de capturar nada o no hay coincidencia con el patrón, devuelve una lista vacía.
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $fichero = "fichero.rar      datos.rar     cosas.rar";
my @archivos = $fichero =~ /(\w+)[.]rar/gi;
say "[@archivos]";                              # [fichero datos cosas]
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

En principio, todo se ejecuta en contexto escalar, pero si Perl ve "algo" distinto, lo ejecutará en contexto de lista. Si lo que hay en la parte izquierda de la asignación es algo que se parece a un contenedor de elementos, entonces es que el usuario espera una lista de valores. Además, y esto es importante, hemos puesto la opción '/g' a la expresión regular. Esa opción indica que queremos que el patrón se pruebe a lo largo de toda la variable $fichero, no que solo capture el primero que encuentre.

Y ahí es donde aparece el tema de los paréntesis.

Normalmente, ponemos una variable array en el lado izquierdo, así que los valores se van almacenando allí (como el caso del último ejemplo con @archivos). Pero también puede haber un par de paréntesis. Ejemplo:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my (undef, $segundo, undef) = $fichero =~ /(\w+)[.]rar/gi;
say "[$segundo]";                                               # datos
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


En tu programa, al poner '($nombre)' ya estás indicando que quieres quedarte con el valor capturado por la expresión regular. Solo un valor, además, ya que la exp. reg. no tiene '/g'.

En la segunda línea, pasa lo mismo con '@nombres'. En este caso, estas solicitando todos los valores posibles que la exp. reg. pueda encontrar, pero ésta no tiene la opción '/g', así que solo devolverá la primera captura.

De hecho, las dos líneas devuelven el mismo valor, porque el patrón así lo indica: los paréntesis deben capturar todo lo que hay ((.+)) entre el principio (^) de la cadena de caracteres hasta el ".rar" del final ($).

Es posible que no sea eso lo que quieres hacer, sino capturar cada nombre de archivo por separado:
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my @archivos = $fichero =~ /(\w+[.]rar)/gi;             # [fichero.rar datos.rar cosas.rar]
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4


Por último, una lindeza de lo que se puede hacer...
Sintáxis: [ Descargar ] [ Ocultar ]
Using perl Syntax Highlighting
my $numero_nombres = () = $fichero =~ /(\w+[.]rar)/gi;  # 3
Coloreado en 0.001 segundos, usando GeSHi 1.0.8.4

Perl está viendo que la expresión regular se debe ejecutar en contexto de lista, debido a la presencia de los paréntesis. Perl busca todas las capturas posibles, por la presencia de la opción '/g'. Luego toma todos esos valores y los intenta meter en... ningún sitio (no hay nada dentro de los paréntesis). Pero, además, Perl ve que en el lado izquierdo hay otra asignación, esta vez en contexto escalar. Y ya sabemos qué pasa cuando una lista o array se ejecuta en contexto escalar: obtenemos el número de elementos. Así que ese valor es lo que al final se almacena en la primera variable.

Más información en la sección "Operadores regex entrecomillados", de perlop (busca por la subsección "Coincidencia en contexto de lista").

Re: Duda con contexto arreglo

NotaPublicado: 2017-12-26 10:59 @499
por MARKO
Muchas gracias, explorer. Me lo dejaste clarísimo, como siempre.