Perl loop bloccato file di lettura?
-
06-07-2019 - |
Domanda
Chiusura di questa domanda. Berrà il toro rosso. Dormire. Codifica e torna con la nuova domanda sculacciata del marchio con i casi di test unitari.
AGGIORNAMENTO: il nuovo file è qui
Anche il file di configurazione è qui
Ho rifattorizzato nuovamente il codice:
sub getColumns {
open my $input, '<', $ETLSplitter::configFile
or die "Error opening '$ETLSpliter::configFile': $!";
my $cols;
while( my $conline = <$input> ) {
chomp $conline;
my @values = split (/=>/, $conline);
if ($ETLSplitter::name =~ $values[0] ) {
$cols = $values[1];
last;
}
}
if($cols) {
@ETLSplitter::columns = split (':', $cols);
}
else {
die("$ETLSplitter::name is not specified in the config file");
}
}
Questo codice muore sempre qui die("$ETLSplitter::name is not specified in the config file");
.
Un altro indizio è che se cambio split (':', $cols);
in split (/:/, $cols);
ottengo questo errore.
perl -wle "
use modules::ETLSplitter;
\$test = ETLSplitter->new('cpr_operator_metric_actual_d2', 'frame/');
\$test->prepareCSV();"
syntax error at modules/ETLSplitter.pm line 154, near "}continue"
Compilation failed in require at -e line 2.
BEGIN failed--compilation aborted at -e line 2.
Soluzione
POST FINALE PER QUESTA DOMANDA: in base ai tuoi ultimi aggiornamenti, credo che il seguente codice illustri come non vi siano problemi nell'uso di /:/
come primo argomento di split
. Sottolinea inoltre che è più semplice leggere il codice quando si usano argomenti per le funzioni piuttosto che fare affidamento su variabili globali:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
for my $varname ( qw( adntopr.cpr.smtref.actv cpr_operator_detail )) {
print $varname, "\n";
print Dumper get_columns(\*DATA, $varname);
}
sub get_columns {
my ($input_fh, $varname) = @_;
while ( my $line = <$input_fh> ) {
chomp $line;
my @values = split /=>/, $line;
next unless $varname eq $values[0];
return [ split /:/, $values[1] ];
}
return;
}
__DATA__
adntopr.cpr.smtref.actv=>3:8:18:29:34:38:46:51:53:149
adntopr.smtsale2=>3:8:16:22:27:37:39:47:52:57:62:82:102:120:138:234:239:244:249:250:259:262:277:282:287:289:304:319:327:331:335:339:340:341:342:353:364:375:386:397:408
cpr_operator_detail=>3:11:18:28:124:220:228:324
cpr_operator_org_unit_map=>7:12
cpr_operator_metric_actual=>8:15:25:33:38:40:51
C:\Temp> tjm
adntopr.cpr.smtref.actv
$VAR1 = [
'3',
'8',
'18',
'29',
'34',
'38',
'46',
'51',
'53',
'149'
];
cpr_operator_detail
$VAR1 = [
'3',
'11',
'18',
'28',
'124',
'220',
'228',
'324'
];
C'è molta cruft in quel codice. Ecco la mia interpretazione di ciò che stai cercando di fare:
AGGIORNAMENTO: data la tua recente osservazione sui caratteri speciali regex nei motivi, se li userai nel motivo per dividere, assicurati di citarli. È anche possibile che $ETLSpliter::name
contenga altri caratteri speciali. Ho modificato il codice per far fronte a tale possibilità.
sub getColumns {
open my $input, '<', $ETLSpliter::configFile
or die "Error opening '$ETLSpliter::configFile': $!");
my @columns;
while( my $conline = <$input> ) {
my @values = split /=>/, $conline;
print "not at: ".$conline;
push @columns, $values[1] if $values[0] =~ /\Q$ETLSpliter::name/;
}
return @columns;
}
UN ALTRO AGGIORNAMENTO:
Quindi, il modello è in effetti /=>/
basato sul tuo commento qui sotto. Poi:
my $conline = q{cpr_operator_detail=>3:11:18:28:124:220:228:324};
my @values = split /=>/, $conline;
use Data::Dumper;
print Dumper \@values;
__END__
C:\Temp> tml
$VAR1 = [
'cpr_operator_detail',
'3:11:18:28:124:220:228:324'
];
Nessun errore ... Nessun avviso Pertanto, sta succedendo qualcos'altro su cui insisti a non mostrarci.
Altre osservazioni:
-
Usa filehandle lessicali e lascia che perl ti dica quali errori potrebbe riscontrare piuttosto che presumere.
-
Dichiara le variabili nel più piccolo ambito applicabile.
-
Non è necessario assegnare
$_
a$conline
nel corpo del ciclo quando è possibile farlo nell'istruzionewhile
. -
Nel codice originale, non hai inserito nulla in
@columns
o fatto nulla di utile con$colData
. -
Riduci la retorica. I computer funzionano secondo il principio di GIGO.
-
Guardando il codice in il link che hai pubblicato , sembra che tu non lo sia consapevole che puoi fare:
use File::Spec::Functions qw( catfile ); ... catfile($ETLSpliter::filepath_results, $ETLSpliter::actual_name);
Inoltre, sembra che tu stia usando un pacchetto in cui l'hash avrebbe fatto il lavoro:
$ETLSpliter{filepath}
Infine, ti rendi conto che Spliter
non è corretto. ITYM: Splitter
.
Altri suggerimenti
Sei sicuro che sia bloccato? Non memorizzi mai dati in @columns
, quindi il tuo codice restituirà sempre un elenco vuoto.
Altre note:
- La tua chiamata
die
dovrebbe includere$!
(errore del sistema operativo). Esistono altri motivi per cui ilopen
potrebbe non riuscire oltre a un file inesistente echomp $conline
ti dirà qual è il vero problema. - Probabilmente dovresti fare un
while (my $conline = <CFILE>)
per sbarazzarti della nuova riga. - Puoi fare
$_
invece di copiare il valore da<
. - Due argomenti
open(my $fh, '<', $filename) or die...
(in particolare con una modalità <=> implicita) ha una forma scadente. È preferibile utilizzare il modulo a tre argomenti (idealmente con un filehandle lessicale): <=>
Cosa c'è in $ETLSpliter::name
- qualsiasi /
caratteri lì dovrebbe essere evitato.
Molti altri problemi nello snippet sono già stati risolti, quindi non ci andrò.
FINALMENTE FATTO FUORI !!!!! Wow Sleep è un potere fantastico.
In ogni caso. Il problema era in $ ETLSplitter :: configFile nel mio messaggio die.
die ('Error opening '.$ETLSpliter::configFile.': '.$!);
Che ha i separatori di percorso winblows '/'. Quindi, poiché stavo producendo una doppia citazione, il perl ha interpretato il '/' nel percorso come schemi. Da qui
die "Error opening some/path/to/ ...
a
... /=>/,
Che ha incasinato l'intero flusso del programma nella subroutine. Ciò è stato risolto facendo questo.
<*>