2016-08-03 8 views
-3

Ich habe ein ttake Skript tha als zwei Dateien gibt:In Perl, warum bekomme ich "Referenz gefunden, wo Even-Size-Liste erwartet", wenn ich versuche, einen Hash zu initialisieren?

  • Eine Extraktion von 200k Linien
  • Die Quelldatei

Ich habe Extraktion gegen Quelle vergleichen: jede Zeile der Extraktion sollte in der Quelle sein. Wenn nicht, muss ich die Zeile eine Protokolldatei protokollieren.

Unter dem Skript:

#!/perl/bin/perl 
use strict; 
use warnings; 
use feature 'say'; 
# Open log file 
open(LOG, '>', 'log.txt'); 
# Start log 
say LOG '['.localtime().'] Début execution'; 
# Declare extraction number of line counter 
my $i_extraction_counter = 1; 
# Define files to be compared (extraction against source) 
my ($extraction_file, $source_file) = @ARGV; 
# Open extraction file 
open my $f_extraction, "<", $extraction_file; 
# Store extraction file in a hash 
my %h_extraction; 
while(defined(my $extr_line = <$f_extraction>)){ 
    $h_extraction{$extr_line} = $extr_line; 
    $i_extraction_counter++; 
} 
# Declare temp hash and counter 
my %h_tmp = {}; 
my $i_counter = 1; 
# Open source file 
open my $f_source, "<", $source_file; 
# For each source line, compare against extraction hash 
while(defined(my $source_line = <$f_source>)){ 
    # If the current line exists in extration hash, stores it in the temp hash & increase counter 
    if(defined($h_extraction{$source_line})){ 
     $h_tmp{$source_line} = $source_line; 
     $i_counter++; 
    } 
    # TO DO : check in elsif if the line should be stored in log (name + firstname OR contract number) 
} 
# If not all lines of extraction has been stored in temp hash = some lines of extraction are not in source file 
if($i_counter < $i_extraction_counter){ 
    # Declare a second temp hash (used to log missing lines) 
    my %h_missing_lines = %h_extraction; 
    # For each line of extraction, check if it exists in the first temp hash. If yes, unset it. Only missing line will remain 
    foreach my $s_line (keys(%h_missing_lines)){ 
     if(defined($h_tmp{$s_line})){ 
      delete($h_missing_lines{$s_line}); 
     } 
    } 
    # For each line of missing lines hash, stores it in log file 
    foreach my $s_line (keys(%h_missing_lines)){ 
     say LOG 'Ligne d\'extraction non présente dans fichier source : '.$s_line; 
    } 
} 
say LOG '['.localtime().'] Fin execution'; 

Bei der Ausführung zeigt diese Meldung auf: Reference found where even-sized list expected at script.pl line 22, <$f_extraction> line 200000.

+3

Dies ist ein gutes Beispiel für einen Fall, in dem 'diagnostics' das Problem besonders gut erklären kann. Probiere 'perl -Mdiagnostics -E'my% h = {} ''. –

+1

@DaveCross: Ich stimme zu, aber 'diagnostics' in das Programm zu verwenden wird große Mengen nutzloser Wörter ausspucken. Verwendet als 'Perl -Mdiagnostics' auf die gleiche Weise, wie Sie' perl -d' verwenden können, ist wesentlich. Halte es einfach aus dem Code heraus. – Borodin

+0

Gute Verwendung für PERL5OPT :-) –

Antwort

10

auf der Leitung 22, die wir haben:

my %h_tmp = {}; 

Ändern Sie diesen an:

my %h_tmp; 

Und es wird dir gut gehen.

Das Problem hier ist - {} wird verwendet, um einen anonymen Hash zu definieren - und eine Referenz zurückgeben.

So könnten Sie tun:

my $hash_ref = {}; 

Und das ist effektiv, was du tust.

my %h_tmp = $hash_ref; 

einen Hash mit einem einzigen Wert wie folgt initialisieren, gibt genau den Fehler, den Sie bekommen, weil ein Hash-Paare Schlüsselwert erwartet.

könnten Sie tun:

my %h_tmp =(); 

Dies würde funktionieren, aber wäre überflüssig - Sie erstellen eine leere Hash oder so.

+0

Das ist es !! Danke :) – VeZoul

+2

@PierrickFlajoulot: Außer dass, während Ihr Code * arbeiten * kann, scheinen Sie Angst vor Leerraum, Einrücken, Layout usw. – Borodin

+0

"perltidy" ist groß und clever :) – Sobrique