Spreadsheet::ParseExcelを使用してファイルを読み取ることができます。すべての行を反復処理し、最初の2つのフィールドをハッシュに格納します。4行ごとに、データを出力に書き込み、ハッシュをクリアできます。
# Adapted from the module documentation
use strict; use warnings;
use Spreadsheet::ParseExcel;
my ($infile, $outfile) = @ARGV;
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse($infile);
die $parser->error unless defined $workbook;
# select the first worksheet
my ($worksheet) = $workbook->worksheets();
# get bounds:
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
# assert that there are at least two fields per row:
$row_max - $row_min >= 1 or die "To few cells per row";
my %data; # accumulate data here
ROW:
for my $row ($row_min .. $row_max) {
# discard every fourth row:
if ($row - $row_min && ($row - $row_min) % 3 == 0) {
...; # write to output
%data = (); # clear cache
next ROW;
}
my ($key, $val) = map {$worksheet->get_cell($row, $_)} $col_min .. $col_max;
$data{$key} = $val;
}
スプレッドシートの作成には、 Spreadsheet::WriteExcelを使用できます。これは次のようになります
# from the module documentation
my $out_workbook = Spreadsheet::WriteExcel->new($outfile);
my $out_worksheet = $out_workbook->add_worksheet;
...;
# write data inside our loop:
my @cols = qw/School Dean No.stu/;
for my $i (0 .. $#cols) {
my $val = delete $data{$cols[$i]} // die "uninitialized value for $cols[$i]";
$out_worksheet->write($row, $i, $val);
}
# do some error handling
if (my @keys = keys %data) {
die "Unexpected field(s) [@keys] encountered";
}
これには、defined-or演算子にperl5v10以降が必要//
です。
アップデート:
正しく説明せずにいくつかの構成を使用して申し訳ありません。
4行ごとに破棄
カウンターを1つから始めておくことができました。ヒットするたびに4
、この行をスキップしてリセットします。しかし、私はすでに行カウンターを持っており、代わりにそれを使用しています。0
最初の行がになるかどうかはわかりません$row_min
。何でもかまいません。したがって$row - $row_min
、実際の行数を取得するために行番号を転置します。ゼロから始まります。
4行ごとに、この実際の数は3で割り切れます。
0 1 2 3 4 5 6 · · ·
* *
したがって、モジュラス演算子を使用できます%
。ただし、0 % $n == 0
すべてに当てはまります$n
(ゼロはすべての数値で均等に割り切れる)ので、ゼロを特殊なケースにする必要があります。これを行うには、除算テストを実行する前に、カウントがゼロでないことを確認します。ゼロを除くすべての数値が真であるため、数値の真実性をテストできます。これはテストにつながります
if ($row - $row_min && ($row - $row_min) % 3 == 0) { ... }
map
式
このmap
関数は、次のいずれかを取ります。
map EXPRESSION, LIST
map { BLOCK } LIST
-ブロックとリストの間にコンマがないことに注意してください。
これは、気の利いたforeachループに非常によく似ています。リスト内の値ごとに$_
、式内のその値に設定されます。次に、式は記憶されている値を返します。リスト内のすべての項目が処理されるmap
と、式の値のリストを返します。
例として、map
リスト内のすべての数値を2乗する式を次に示します。
my @squares = map { $_ * $_ } 1 .. 10; # 1, 4, 9 16, .. 100
行内のすべてのセル値をフェッチするためにを使用しmap
ます。すべての列のリスト($col_min .. $col_max
)を指定すると、map
ブロックは現在の行のその列のセルをフェッチします。
したがってmap
、「Lvalue」リストに割り当てたセルのリストを返します($key, $val)
。リストの割り当てにより$key
、最初の$val
セルの値と2番目のセルの値が割り当てられます。
プレーンforeach
ループで書かれていると、これは次のようになります。
my @cells;
for my $col ($col_min .. $col_max) {
push @cells, $worksheet->get_cell($row, $_);
}
my $key = shift @cells;
my $val = shift @cells;
データ構造を見る
デバッグのためにデータ構造をダンプするデフォルトの方法は、Data::Dumperモジュールを使用することです。ハッシュまたは配列を確認する場合は、必ずデータ構造を参照として渡してください。例えば:
use Data::Dumper; # at the top of your script
warn Dumper \%data; # where ever you need the info
より良いフォーマットが必要な場合は、いつでも独自のフォーマットを作成できます。
printf "Contents of %%data for row %d:\n", $row - $row_min;
for my $key (sort keys %data) {
printf "%10s:%s\n", $key, $data{$key}
}
このsort
関数の使用法は、引数をアルファベットの昇順でソートします。