我在为解析 CSV 文件而编写的 Perl 脚本中做错了什么?

发布于 2024-09-28 04:20:18 字数 1631 浏览 3 评论 0原文

我有两个脚本正在尝试使用 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";
}

I have two scripts in which I'm experimenting with CSV_XS. In the first, I hard-coded everything: source directory, filename, and the csv delimiter I wanted to look for. The script works great. In the second, however, I try to dynamically discover as much as possible. That script seems to run, but it outputs nothing.

I'm having trouble figuring out why, and I was hoping you fine Perl folks wouldn't mind lending a second set of eyes to the problem:

First, the successful script:

#!/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";
}

And second, the "failing" script:

#!/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";
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦年海沫深 2024-10-05 04:20:18

这行看起来有点可疑:

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

我认为你不想把那些 || 放在那里。它的作用是检查 $input_dir 是否为真,如果不是,则检查 "/" 是否为真(它总是如此) 。您的 $input_dir 可能始终为 true,因此您只需打开 $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;

This line looks kind of suspect:

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

I don't think you want to put those || in there. What that does is check to see if $input_dir is true, then if it isn't, it check to see if "/" is true (which it always is). Your $input_dir is likely always true, so you're just opening the $input_dir.

You should be using File::Spec to create your fully-qualified files:

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

This will "do the right thing" in putting a / where appropriate (or, if you're on Windows, \). Then pass that in to your open() command.

Further, you should be using lexical filehandles and directory handles, along with the three-option open():

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

Lexical filehandles are much safer, as they can't get overridden by some other module defining a FILE filehandle. Three-option open() is easier to understand and isn't prone to error when you have a filename that has a > or < or | in it.

If you want to get really crazy, put use autodie; at the top, so you don't even have to check for the return value of open() or opendir():

use autodie;
open my $fh, '<', $fullfile;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文