4

いくつかの Excel ファイルを 1 つの複数のシートにマージする必要があります。新しいファイルのシート名はあまり気にしません。

これを実行する予定のコンピューターに Excel がありません。そのため、Win32 OLE を使用できません。このコードhttps://sites.google.com/site/mergingxlsfiles/を実行しようとしましたが、機能しません。新しい空の Excel ファイルを取得します。

http://www.perlmonks.org/?node_id=743574を実行しようとしましたが、新しい Excel ファイルのファイルを 1 つしか取得できませんでした。

入力した 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(2という名前のシートは1つだけ)、3.xls(3という名前のシートは1つだけ)

次のようにスクリプトを起動しました。

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

結果: results-20121024.xls は何も空にしません。

それから私は試しました

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

そしてそれはうまくいきました。シート名の追加中に失敗する理由がわかりません

4

1 に答える 1

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をテストするために利用できません。

于 2012-10-24T18:48:11.860 に答える