您可以使用Spreadsheet::ParseExcel来读取您的文件。遍历所有行,并将前两个字段存储在哈希中。在每四行,您可以将数据写入输出,并清除哈希:
# 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";
}
对于定义或运算符,这需要 perl5 v10 或更高版本//
。
更新:
很抱歉我使用了一些结构而没有正确解释它们。
丢弃每一行
我可以保留一个从一个开始的计数器。每次它命中时4
,我都会跳过这一行,然后重置它。但是,我已经有一个行计数器,我用它来代替。我不知道第一行会是0
,因为$row_min
可能是任何东西。所以我转置行号$row - $row_min
以获得实际的行数。它从零开始。
每第四行,这个实际计数可以被三整除:
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
对列表中所有数字求平方的表达式:
my @squares = map { $_ * $_ } 1 .. 10; # 1, 4, 9 16, .. 100
我使用map
来获取行内的所有单元格值:我指定所有列的列表 ( $col_min .. $col_max
),并且map
块获取该列中当前行的单元格。
所以map
返回一个单元格列表,我将其分配给“左值”列表($key, $val)
。列表赋值导致$key
具有第一个$val
单元格的值和第二个单元格的值。
用一个普通的循环编写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
函数的这种用法将按字母升序对其参数进行排序。