我是perl的新手,所以如果我的问题很简单,请接受我的道歉。我有一个非常大的文件,其数据如下所示:
Date, Time, Data1, Data2, Data3
1/4/1999,9:31:00 AM,blah, blah, blah
1/4/1999,9:32:00 AM,blah, blah, blah
1/4/1999,9:33:00 AM,blah, blah, blah
我有一个名为'cities.txt'的文件,其中有一个位于不同行的城市列表,行末有逗号。
即
Boston,
Atlanta,
Seattle,
每个城市在同一目录中都有自己的文件,该文件具有以下命名约定'Boston 1 Minute Moisture Data.txt'。我想首先阅读'cities.txt'文件,并为该文件中出现的每个城市找到相关的湿度数据文件,并提取两组日期之间的所有数据(行)(START和END日期)并将其保存到另一个文件。日期位于第一列。
我已阅读以下帖子中的评论,但我仍然非常困惑。
How do I efficiently parse a CSV file in Perl?
我在网上使用一些例子写了一个简单的脚本。首先,我只是想看看我是否正确使用该模块。所以我想做的就是让解析器解析字段并计算特定列的总和。
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new();
my $file = 'Boston 1 Minute Moisture Data.csv';
my $sum = 0;
open(my $data, '<', $file) or die "Could not open '$file'\n";
while (my $line = <$data>) {
chomp $line;
if ($csv->parse($line)) {
my @columns = $csv->fields();
$sum += $columns[3];
} else {
warn "Line could not be parsed: $line\n";
}
}
print "$sum\n";
结果是get是“Line无法解析:$ line \ n”。由于某种原因,解析器不解析字段。有什么想法吗?
我也尝试了以下代码:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $file = 'Boston 1 Minute Moisture Data.csv';
my $csv = Text::CSV->new();
open (CSV, "<", $file) or die $!;
while (<CSV>) {
if ($csv->parse($_)) {
my @columns = $csv->fields();
#print "@columns\n";
print fields[1];
} else {
my $err = $csv->error_input;
print "Failed to parse line: $err";
}
}
close CSV;
我对文件中的每一行都得到以下结果:
print()在test2.pl第16行第9326行的未打开的文件句柄字段上。
答案 0 :(得分:2)
问题解决方案的整体结构如下:
您尚未指定每个城市是否有单独的保存文件。
您的试用解决方案正确使用Text::CSV模块 - 这很好。您还需要某种方法来解析日期值 - 输入值(开始和结束日期)和扫描值(来自水分数据)。我可能会使用POSIX::strptime模块,但您可以使用任何其他日期和时间操作模块。
这不是很好的Perl - 但是下面的代码似乎在运行时起作用:
$ perl scan.pl 1/3/1999 30/4/1999
Boston,1/4/1999,9:31:00 AM,blah, blah, blah
Boston,1/4/1999,9:32:00 AM,blah, blah, blah
Boston,1/4/1999,9:33:00 AM,blah, blah, blah
Atlanta,1/4/1999,9:31:00 AM,blah, blah, blah
Atlanta,1/4/1999,9:32:00 AM,blah, blah, blah
Atlanta,1/4/1999,9:33:00 AM,blah, blah, blah
Seattle,1/4/1999,9:31:00 AM,blah, blah, blah
Seattle,1/4/1999,9:32:00 AM,blah, blah, blah
Seattle,1/4/1999,9:33:00 AM,blah, blah, blah
$ perl scan.pl 1/3/2000 30/4/2000
$
(考虑到问题中的城市数据,以及每个城市的示例数据的副本。我假设正常(例如英国)样式日期与序列日,月,年。如果您正在使用美式风格日期,您需要进行调整。如果您使用无效日期,您将收到错误; get_date()
中的错误处理不存在。)
#!/usr/bin/env perl
use strict;
use warnings;
use POSIX::strptime;
use Text::CSV;
my $cities = "cities.txt";
die "Usage: $0 start-date end-date\n" if scalar(@ARGV) != 2;
my $start = get_date($ARGV[0]);
my $end = get_date($ARGV[1]);
{
open my $cfh, "<", $cities or die "Failed to open $cities ($!)";
while (<$cfh>)
{
chomp;
my $city = $_;
$city =~ s/\s*,.*//;
$city =~ s/^\s*//;
my $moisture = "$city 1 Minute Moisture Data.txt";
open my $mfh, "<", $moisture or die "Failed to open $moisture ($!)";
process_file($mfh, $moisture, $city);
}
}
sub get_date
{
my($str) = @_;
my ($mday, $mon, $year) = ( POSIX::strptime($str, '%d/%m/%Y') )[3,4,5];
return (($year + 1900) * 100 + ($mon + 1)) * 100 + $mday;
}
sub process_file
{
my($fh, $file, $city) = @_;
my $csv = Text::CSV->new() or die "Failed to create Text::CSV object";
my $line = <$fh>;
die "Unexpected EOF in $file" unless defined $line;
while ($line = <$fh>)
{
chomp $line;
die "Failed to parse line <<$line>>" unless $csv->parse($line);
my @columns = $csv->fields();
die "Insufficient columns in <<$line>>" if scalar(@columns) < 1;
my $date = get_date($columns[0]);
print "$city,$line\n" if ($date >= $start && $date <= $end);
}
}