Perl如何在一个(多个工作表)中合并两个或多个excel文件?

时间:2012-10-24 13:48:16

标签: perl excel file merge

我需要将一些excel文件合并为一张,多张。 我不太关心新文件中的工作表名称。

我计划运行此计算机上没有Excel。所以我不能使用Win32 OLE。 我尝试运行此代码https://sites.google.com/site/mergingxlsfiles/但它无效,我得到一个新的空excel文件。

我尝试运行http://www.perlmonks.org/?node_id=743574,但我只获得了新excel文件中的一个文件。

我的输入excel文件有一些法语字符(例如é)我相信这些是cp1252。

使用的代码:

    #!/usr/bin/perl -w
    use strict;
    use Spreadsheet::ParseExcel;
    use Spreadsheet::WriteExcel;
    use File::Glob qw(bsd_glob);
    use Getopt::Long;
    use POSIX qw(strftime);

    GetOptions(
        'output|o=s' => \my $outfile,
        'strftime|t' => \my $do_strftime,
    ) or die;

    if ($do_strftime) {
        $outfile = strftime $outfile, localtime;
    };

    my $output = Spreadsheet::WriteExcel->new($outfile)
        or die "Couldn't create '$outfile': $!";

    for (@ARGV) {
        my ($filename,$sheetname,$targetname);
        my @files;
        if (m!^(.*\.xls):(.*?)(?::([\w ]+))$!) {
            ($filename,$sheetname,$targetname) = ($1,qr($2),$3);
            warn $filename;
            if ($do_strftime) {
                $filename = strftime $filename, localtime;
            };
            @files = glob $filename;
        } else {
            ($filename,$sheetname,$targetname) = ($_,qr(.*),undef);
            if ($do_strftime) {
                $filename = strftime $filename, localtime;
            };
            push @files, glob $filename;
        };

        for my $f (@files) {
            my $excel = Spreadsheet::ParseExcel::Workbook->Parse($f);
            foreach my $sheet (@{$excel->{Worksheet}}) {
                if ($sheet->{Name} !~ /$sheetname/) {
                    warn "Skipping '" . $sheet->{Name} . "' (/$sheetname/)";
                    next;
                };
                $targetname ||= $sheet->{Name};
                #warn sprintf "Copying %s to %s\n", $sheet->{Name}, $targetname;

                my $s = $output->add_worksheet($targetname);
                $sheet->{MaxRow} ||= $sheet->{MinRow};
                foreach my $row ($sheet->{MinRow} .. $sheet->{MaxRow}) {
                    my @rowdata = map {
                        $sheet->{Cells}->[$row]->[$_]->{Val};
                    } $sheet->{MinCol} ..  $sheet->{MaxCol};
                    $s->write($row,0,\@rowdata);
                }
            }
        };
    };

    $output->close;

我有2个excel文件名为:2.xls(只有1张名为2的纸),3.xls(只有1张名为3)

我按原样启动了脚本:

xlsmerge.pl -s -o results-%Y%m%d.xls 2.xls:2 3.xls:3

结果:结果-20121024.xls中没有任何内容。

然后我试了

xlsmerge.pl -s -o results-%Y%m%d.xls 2.xls 3.xls 

它有效。 我不确定为什么在添加Sheetname

时失败了

1 个答案:

答案 0 :(得分:3)

此脚本中似乎存在错误:

if (m!^(.*\.xls):(.*?)(?::([\w ]+))$!) {
     ($filename,$sheetname,$targetname) = ($1,qr($2),$3);
     ...

在我看来,该行的目标是允许以

形式提供参数
spreadsheet.xls:source_worksheet

或以另一种形式允许指定目标表的名称:

spreadsheet.xls:source_worksheet:target_worksheet

最后一个分组似乎是为了捕获最后一个可选参数:(?::([\w ]+))。唯一的问题是,这种分组不是可选的。因此,当您仅指定源表而不指定目标时,正则表达式无法匹配,并且它落入备份行为,即将整个参数视为文件名。但这也失败了,因为你没有名为2.xls:2的文件。

解决方案是在正则表达式中的最后一个组之后引入?修饰符以使其可选:

if (m!^(.*\.xls):(.*?)(?::([\w ]+))?$!) {
     ($filename,$sheetname,$targetname) = ($1,qr($2),$3);
     ...

当然,这可能不是唯一的问题。如果脚本发布时出现错误,则可能还有其他错误。我目前没有可用于测试它的Perl。