2012-03-05 40 views
5

Me gustaría utilizar una "expresión regular compilada" (es decir, una expresión en el formato qr/../) como clave para una estructura hash.reconociendo "tipo" de claves hash

Para discernir entre cadenas constantes y estas expresiones regulares cuando se itera sobre los Keyes de hash, que estaba tratando de utilizar ref() o is_regexp(), pero el primero devuelve una cadena nula, y este último no funciona. Me temo que me está perdiendo algo fundamental sobre Perl refs vs. escalares.

Aparte de eso, mi solución parece funcionar. ¿Es demasiado feo de todos modos? Cualquier propuesta alternativa es bienvenida.

algo de código para entender ref() función:

my $regex = qr/foo/; 
printf "ref(\$regex): %s \n", ref($regex); 
printf "is_regexp(\$regex): %d \n", is_regexp($regex); 
# ref($regex): Regexp 
# is_regexp($regex): 1 

my $scalar = 3; 
printf "ref(\$scalar): [%s] \n", ref($scalar); 
# ref($scalar): [] 

my %my_hash = ('name', 'Becky', 'age', 23); 
for my $k (keys %my_hash) { 
    printf "%s [%s] -> %s [%s] \n", $k, ref($k), $my_hash{$k}, ref($my_hash{$k}); 
} 
# name [] -> Becky [] 
# age [] -> 23 [] 
+5

Las claves en un hash son cadenas. 'ref' siempre devolverá' undef' para esos. Si usa algo como una clave que no es una cadena, se convierte en cadena. – Qtax

Respuesta

7

Como Qtax señala en los comentarios, claves hash de Perl son siempre cadenas: si utiliza algo distinto de una cadena como una clave hash, se convierte primero a una cadena.

En otro comentario se escribe:

"He leído las definiciones de contador de un archivo de configuración, quiero ser capaz de soportar una sintaxis patrón, por ejemplo: McDouglas, McDonald,/Mc [A-Za .-z] */I a continuación, leí los valores del contador de archivos de texto, y puedo actualizar los contadores pertinentes en consecuencia: McDonald 23 McIntosh 11"

Si entiendo este derecho, una solución simple podría ser la de almacenar las expresiones regulares compiladas en otro hash, codificado en su representación de cadena:

my @patterns = (
    'McDouglas', 
    'McDonald', 
    'Mc[A-Za-z]*', 
); 

my %regexps = map +($_ => qr/^$_$/), @patterns; 
my %counters; 

while (<>) { 
    while (my ($pat, $re) = each %regexps) { 
     $counters{$pat}++ if /$re/; 
    } 
} 

foreach my $pat (@patterns) { 
    print "$pat: ", ($counters{$pat} || 0), "\n"; 
} 
2

¿Hay algo malo con el uso Tie::RegexpHash? Se le ahorra tener que reinventar la rueda :)

use Tie::RegexpHash; 

my %hash; 

tie %hash, 'Tie::RegexpHash'; 

$hash{ qr/^5(\s+|-)?gal(\.|lons?)?/i } = '5-GAL'; 

$hash{'5 gal'};  # returns "5-GAL" 
$hash{'5GAL'};  # returns "5-GAL" 
$hash{'5 gallon'}; # also returns "5-GAL" 
+0

Si bien el paquete que sugiere es bastante interesante, realiza algo diferente de lo que necesito. En mi caso, también podría almacenar las cadenas simples que definen las expresiones regulares (pero perdería la precompilación de expresiones regulares). Un caso donde los dos enfoques chocan es cuando uno necesita almacenar expresiones regulares superpuestas parcialmente entre sí. – AndreaG

+0

@AndreaG: Proporcione un ejemplo de lo que quiere decir. – Zaid

+0

Leí definiciones de contador de un archivo de configuración; Quiero ser capaz de soportar algunas sintaxis de patrones, por ejemplo: McDouglas, McDonald,/Mc [A-Za-z] * /. Luego leo los valores del contador de los archivos de texto y actualizo los mostradores relevantes en consecuencia: McDonald 23 McIntosh 11 – AndreaG

Cuestiones relacionadas