1

私は Perl を初めて使用し、精神的な障害にぶつかりました。以下に示すように、タブ区切りファイルから情報を抽出する必要があります。

#name  years risk total
 adam  5     100  200
 adam  5     50   100
 adam  10    20   300
 bill  20    5    100
 bill  30    10   800

この例では、タブ区切りのファイルに、投資期間、危険にさらされた金額、および投資終了時の合計が表示されます。

このファイルを解析し、各名前 (例: adam ) について、投資年数の合計5+5を計算し、収益の合計(200-100) + (100-50) + (300-20)を計算します。また、名前ごとの合計 (200、100、300) も保存したいと思います。

これまでに試したことは次のとおりです。

my $filename;
my $seq_fh;

open $seq_fh, $frhitoutput 
    or die "failed to read input file: $!";

while (my $line = <$seq_fh>) {

    chomp $line;
    ## skip comments and blank lines and optional repeat of title line

    next if $line =~ /^\#/ || $line =~ /^\s*$/ || $line =~ /^\+/;

    #split each line into array
    my @line = split(/\s+/, $line);
    my $yeartotal = 0;
    my $earning   = 0;

    #$line[0] = name
    #$line[1] = years
    #$line[2] = start
    #$line[3] = end

    while (@line[0]){

        $yeartotal += $line[1];
        $earning   += ($line[3]-$line[2]);
    }
}

私が間違っていた場所のアイデアはありますか?

4

5 に答える 5

7

このText::CSVモジュールは、タブ区切りのデータを読み取るために使用できます。split多くの場合、引用やエスケープなどに関しては、手動で何かをハックしようとするよりもはるかに優れています。

于 2012-10-24T09:55:12.700 に答える
6

あなたはここで間違っています:while(@line[0]){

私はします:

my $seq_fh;
my %result;
open($seq_fh, $frhitoutput) || die "failed to read input file: $!";
while (my $line = <$seq_fh>) {
    chomp $line;
    ## skip comments and blank lines and optional repeat of title line
    next if $line =~ /^\#/ || $line =~ /^\s*$/ || $line =~ /^\+/;
    #split each line into array
    my @line = split(/\s+/, $line);
    $result{$line[0]}{yeartotal} += $line[1];
    $result{$line[0]}{earning} += $line[3] - $line[2];
}
于 2012-10-24T08:15:16.950 に答える
3

次のようなハッシュを使用する必要があります。

my %hash;
while (my $line = <>) {

    next if $line =~ /^#/;

    my ($name, $years, $risk, $total) = split /\s+/, $line;

    next unless defined $name and defined $years
            and defined $risk and defined $total;

    $hash{$name}{years}    += $years;
    $hash{$name}{risk}     += $risk;
    $hash{$name}{total}    += $total;
    $hash{$name}{earnings} += $total - $risk;
}

foreach my $name (sort keys %hash) {

    print "$name earned $hash{$name}{earnings} in $hash{$name}{years}\n";
}
于 2012-10-24T08:17:56.637 に答える
2

Perlの強力なコマンドラインオプションを探索する絶好の機会です!:)

コード

:このコードはコマンドラインのワンライナーである必要がありますが、この方法で読む方が少し簡単です。適切なスクリプトファイルに書き込むときは、厳密な警告と警告を有効にし、もう少し適切な名前を使用する必要があります。このバージョンはstrictではコンパイルされません。宣言する必要がありますour $d

#!/usr/bin/perl -nal

# collect data
$d{$F[0]}{y} += $F[1];
$d{$F[0]}{e} += $F[3] - $F[2];

# print summary
END { print "$_:\tyears: $d{$_}{y},\tearnings: $d{$_}{e}" for sort keys %d }

出力

adam:   years: 20,  earnings: 430
bill:   years: 50,  earnings: 885

説明

ここでは、-n基本的にコードが入力レコードを反復処理できるようにする(-l行を使用するように指示する)スイッチを使用します。この-aスイッチにより、perlは行を配列に分割できます@F。簡略化されたバージョン:

while (defined($_ = <STDIN>)) {
    chomp $_;
    our(@F) = split(' ', $_, 0);

    # collect data
    $d{$F[0]}{y} += $F[1];
    $d{$F[0]}{e} += $F[3] - $F[2];
}

%dは、名前をキー、ハッシュ参照を値として持つハッシュであり、年(y)と収益()が含まれていますe

ENDブロックは、入力ラインの処理と出力が終了した後に実行されます%d

Oを使用Deparseして、実際に実行されるコードを表示します。

book:/tmp memowe$ perl -MO=Deparse tsv.pl
BEGIN { $/ = "\n"; $\ = "\n"; }
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    our(@F) = split(' ', $_, 0);
    $d{$F[0]}{'y'} += $F[1];
    $d{$F[0]}{'e'} += $F[3] - $F[2];
    sub END {
        print "${_}:\tyears: $d{$_}{'y'},\tearnings: $d{$_}{'e'}" foreach (sort keys %d);
    }
    ;
}
tsv.pl syntax OK
于 2012-10-24T09:00:52.743 に答える
0

固定幅ファイルのようですが、unpackそのために使用します

于 2012-10-24T13:46:03.547 に答える