Что я делаю неправильно в моем скрипте Perl, написанном для разбора файла CSV? - PullRequest
0 голосов
/ 20 октября 2010

У меня есть два сценария, в которых я экспериментирую с CSV_XS. Во-первых, я жестко запрограммировал все: исходный каталог, имя файла и разделитель csv, который я хотел найти. Сценарий прекрасно работает. Во втором, однако, я стараюсь динамически обнаружить как можно больше. Этот скрипт, кажется, работает, но ничего не выводит.

У меня проблемы с выяснением причин, и я надеялся, что вы прекрасно справляетесь с Perl, не возражаете бросить второй взгляд на проблему:

Во-первых, успешный скрипт:

#!/usr/bin/perl -w
use Text::CSV_XS;
my @records;
my $file = 'Data/space.txt';
my $csv=Text::CSV_XS->new({ sep_char => " " });

open(FILE,$file) || die "Couldn't open $file: $!\n";
while (<FILE>){
 $csv->parse($_);
 push(@records,[$csv->fields]);
}
close FILE;

foreach (@records){
 print $_->[0], ",", $_->[1], ",", $_->[2], ",", $_->[3], ",", $_->[4], "\n";
}

И, во-вторых, «сбойный» скрипт:

#!/usr/bin/perl -w
use Text::CSV_XS;

$input_dir = $ARGV[0]; #I pass "Data" on the command line
my @records;

opendir(DIR, $input_dir) || die "cannot open dir $input_dir: $!";
my @filelist = grep {$_ ne '.' && $_ ne '..'} readdir DIR;
closedir DIR;

foreach $file (@filelist){
 print "Input file='",$input_dir,"/",$file,"'\n";
 if ($file =~ /comma/) {$sep=','}
    elsif ($file =~ /pipe/) {$sep='|'}
    elsif ($file =~ /space/) {$sep=' '}
    else {die "Cannot identify separator in $file: $!";}
 print "Delimiter='",$sep,"'\n";   
 open(FILE,$input_dir||"/"||$file) || die "Couldn't open $file: $!\n";
 my $csv=Text::CSV_XS->new({ sep_char => $sep });
 while (<FILE>){
  $csv->parse( $_ );
     push(@records,[$csv->fields]);
  print "File Input Line:'", $_ ,$csv->fields,"'\n";
 };
 close FILE;
}

foreach $record (@records){
 print $record->[0], ",", $record->[1], ",", $record->[2], ",", $record->[3], ",", $record->[4], "\n";
}

1 Ответ

4 голосов
/ 20 октября 2010

Эта строка выглядит подозрительно:

open(FILE,$input_dir||"/"||$file) || die "Couldn't open $file: $!\n";

Не думаю, что вы хотите поместить туда эти ||.То, что он делает, это проверяет, является ли $input_dir истиной, тогда, если это не так, он проверяет, является ли "/" истиной (что всегда так).Ваш $input_dir, вероятно, всегда верен, поэтому вы просто открываете $input_dir.

. Вы должны использовать File::Spec для создания ваших полностью определенных файлов:

my $fullfile = File::Spec->catfile( $input_dir, $file );
open( FILE, $fullfile ) || die "Couldn't open $fullfile: $!\n";

Это будет «делать правильные вещи», помещая /, где это уместно (или, если вы используете Windows, \).Затем передайте это в вашу команду open().

Далее, вы должны использовать лексические дескрипторы файлов и директории, а также три опции open():

open my $fh, '<', $fullfile or die "Could not open file $fullfile: $!\n";

Лексические дескрипторы файловгораздо безопаснее, поскольку они не могут быть переопределены каким-либо другим модулем, определяющим дескриптор файла FILE.Три варианта open() проще для понимания и не подвержены ошибкам, если у вас есть имя файла с > или < или | в нем.

Если вы хотите получитьдействительно сумасшедший, поставьте use autodie; вверху, чтобы вам даже не приходилось проверять возвращаемое значение open() или opendir():

use autodie;
open my $fh, '<', $fullfile;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...