2012-08-29 6 views
6

Voglio creare dinamicamente un hash %detail, senza utilizzare una dichiarazione eval. Questo codice funziona correttamente con un'istruzione eval, ma esiste un modo migliore per eseguire questa operazione senza utilizzare eval?

my @input=('INFO: Vikram 32 2012','SAL: 12000$','ADDRESS: 54, junk, JUNK'); 

my %matching_hash= (
        qr/^INFO:\s*(\S+)\s+(\S+)\s+(\S+)/ =>['name','age','joining'], 
        qr/^SAL:\s*(\S+)/ => ['salary'], 
        qr/ADDRESS:\s*(.*)/ =>['address'] 
        ); 
my %detail; 
while(my ($regex, $array) = each(%matching_hash)) { 
    foreach (@input){ 
     if(/$regex/) { 
      for(my $i=0;$i<=$#$array; $i++) { 
       $j=$i+1; 
       eval '$detail{$array->[$i]} = $$j'; 
      } 
     } 
    } 
} 
use Data::Dumper; 

print Dumper(\%detail); 
++++++++++++++ 

$VAR1 = { 
      'name' => 'Vikram', 
      'address' => '54, junk, JUNK', 
      'age' => '32', 
      'joining' => '2012', 
      'salary' => '12000$' 
     }; 
+0

Non penso che la tua dichiarazione di valutazione funzionerà se si usa strict' (ho dovuto rimuoverlo dal mio test per ottenere l'output desiderato). –

risposta

5

Modificare il ciclo for:

for(my $i=0;$i<=$#$array; $i++) { 
    $j=$i+1; 
    eval '$detail{$array->[$i]} = $$j'; 
} 

da:

@detail{@{$array}} = ($_ =~ $regex); 
1

È possibile utilizzare i due array @LAST_MATCH_START e @LAST_MATCH_END (vedi perldoc perlvar) insieme substr invece di $1, $2.... Qualcosa di simile a

$detail{ $array->[$i] } = substr $_, $LAST_MATCH_START[$j], $LAST_MATCH_END[$j] - $LAST_MATCH_START[$j]; 
+0

concordato, tranne che per l'inglese. – hobbs

14

parte Rilevante:

if(my @m = /$regex/) { 
    for(my $i=0;$i<=$#$array; $i++) { 
     $detail{$array->[$i]} = $m[$i];    
    } 
} 
2

Se è possibile utilizzare ultima versione di Perl, vedere a questa notazione (?<name>...) in regexp perlre docs E 'più chiaro quindi utilizzando $ 1, $ 2, $ 3, ecc

SCRIPT

use v5.14; 
use Data::Dumper; 

my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 

my %matching_hash= (
    qr/^INFO:\s*(?<name>\S+)\s+(?<age>\S+)\s+(?<joining>\S+)/ => [ 'name', 'age', 'joining' ], 
    qr/^SAL:\s*(?<salary>\S+)/        => [ 'salary' ], 
    qr/ADDRESS:\s*(?<address>.*)/        => [ 'address' ], 
); 

my %detail; 
while (my ($regex, $array) = each %matching_hash) { 

    INPUT: 
    foreach my $input (@inputs) { 

     next INPUT if not $input =~ m{$regex}; 

     for my $name (@$array) { 
      $detail{$name} = $+{$name}; 
     } 
    } 
} 

say Dumper(\%detail); 

USCITA

$VAR1 = { 
      'name' => 'Vikram', 
      'address' => '54, junk, JUNK', 
      'age'  => '32', 
      'joining' => '2012', 
      'salary' => '12000$' 
     }; 
+2

Non dovrebbe aver bisogno degli array mappati se userà corrispondenze denominate solo '@detail {chiavi% +} = valori% + se $ input = ~ m {$ regex};' o anche '% detail =% + se $ input = ~ m {$ regex}; '. Quindi puoi inserire le regex in una struttura che è molto più adatta per l'iterazione, una lista/array. +1 per quello che avrei suggerito. – Axeman

+0

'% detail =% + se $ input = ~ m {$ regex};' non funziona, getta via ciò che è già in '% detail'. –

1

Utilizzando named capture groups, è possibile eliminare la necessità di %matching_hash essere un hash. Eliminando allo stesso tempo la necessità di utilizzare le variabili numeriche o assegnando il risultato della corrispondenza in un array. Questo perché memorizzerà le informazioni rilevanti in %+.

use 5.10.1; 

my @match = (
    qr'^INFO:\s*(?<name>\S+)\s+(?<age>\S+)\s+(?<joining>\S+)', 
    qr'^SAL:\s*(?<salary>\S+)', 
    qr'ADDRESS:\s*(?<address>.*)', 
); 

sub get_details{ 
    my %detail; 

    for my $input (@_) { 
    for my $match (@match){ 
     next unless $input =~ $match; 
     @detail{keys %+} = values %+; 
     last; 
    } 
    } 

    return \%detail; 
} 

use Data::Dumper; 
my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 
say Dumper get_details @inputs 

Si può ottenere ancora più semplice se si combinano le vostre qr 's in uno solo.

use 5.10.1; 

my $match= qr" 
    ^INFO: \s* (?<name>\S+) \s+ (?<age>\S+) \s+ (?<joining>\S+) 
    | ^SAL: \s* (?<salary>\S+) 
    | ADDRESS: \s* (?<address>.*) 
"x; 

sub get_details{ 
    my %detail; 

    for my $input (@_) { 
    $input =~ $match; 
    @detail{keys %+} = values %+; 
    } 

    return \%detail; 
} 

use Data::Dumper; 
my @inputs = ('INFO: Vikram 32 2012', 'SAL: 12000$','ADDRESS: 54, junk, JUNK'); 
say Dumper get_details @inputs 
Problemi correlati