0

perlを使用してxlsファイルを解析したい。xlsファイルは、解析を少しトリッキーにする構造に従っています。

      col1      col2
row1  School    1
row2  Dean      John
row3  No.stu.   55
row4  some irrelevant stuff 
row5  School2   2
row6  Dean      Tony 
row7  No. stu.  60 
row8  some irrelevant stuff

私が達成したい出力は次のとおりです。

      col1 col2 col3
row1 School Dean No.stu. 
row2 1      John  55
row3 2      Tony  60 

私がこれまで勉強してきたモジュールはSpreadsheet::ParseExcelです。他のモジュールが私をここから助けてくれる可能性がありますか?よろしく、

私の問題を部分的に解決する潜在的な方法を提供する@amonreplyに感謝します。しかし、Perlの初心者として、私はコードを消化するのに多くの困難を抱えています。

解析部分が頭上から始まりますがROW:、それは何に使用されますか?そして、私は本当に知りません

my ($key, $val) = map {$worksheet->get_cell($row, $_)} $col_min .. $col_max;

Spreadsheet::ParseExcelドキュメント に記載されているものとして解釈できますか?

for my $row ( $row_min .. $row_max ) {

for my $col ( $col_min .. $col_max ) {

my $cell = $worksheet->get_cell( $row, $col );}

また、出力部分にジャンプする前に、何が解析されたかを確認できますか?とにかく、テーブルに蓄積された変数を出力する方法はあります%dataか?私はしばらく苦労してきました。

本当にありがとうございました!

4

1 に答える 1

2

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関数の使用法は、引数をアルファベットの昇順でソートします。

于 2013-03-24T13:04:41.007 に答える