Разобрать файл с разделителями-запятыми на основе даты начала и окончания - PullRequest
0 голосов
/ 21 марта 2011

Я новичок в 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  

У меня есть файл с именем 'towns.txt', в котором находится список городов, расположенных в разных строках с запятой в конце строки.

т.е.

Boston,  
Atlanta,  
Seattle,  

Каждый город имеет свой собственный файл в том же каталоге, который имеет следующее соглашение об именах «Boston 1 Minute Moisture Data.txt». Я хочу сначала прочитать файл 'towns.txt', и для каждого города, который появляется в этом файле, найти связанный файл данных о влажности и извлечь все данные (строки) между двумя наборами дат, включая даты начала и окончания, и включая их. и сохранить это в другой файл. Дата находится в первом столбце.

Я прочитал комментарии, сделанные в следующем посте, но я все еще в замешательстве.

Как эффективно проанализировать файл CSV в 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 \ 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.

1 Ответ

2 голосов
/ 21 марта 2011

Общая структура решения вашей проблемы выглядит следующим образом:

  • открыть города.txt
  • для каждой строки, прочитанной из city.txt
    • открыть файл «$ city 1 Minute Moisture Data.txt»
    • для каждой строки из файла влажности
      • если дата строки попадает в диапазон
      • добавить строку в файл сохранения

Вы не указали, существует ли отдельный файл сохранения для города.

Ваши пробные решения правильно используют модуль 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...