你能试试下面的 Perl 脚本吗:
#! /usr/bin/env perl
package Main;
use feature qw(say);
use strict;
use warnings;
use Spreadsheet::ParseXLSX;
use Excel::CloneXLSX::Format qw(translate_xlsx_format);
use Excel::Writer::XLSX;
{
my $self = Main->new(
input_file => 'x.xlsx',
skip_cols => [4],
);
$self->scan_input_file();
$self->write_chunks();
say "Done";
}
sub close_chunk_file {
my ( $self ) = @_;
if ($self->{workbook}) {
$self->{workbook}->close();
}
}
sub new {
my ( $class, %args ) = @_;
return bless \%args, $class;
}
sub scan_input_file {
my ( $self ) = @_;
my $parser = Spreadsheet::ParseXLSX->new;
my $workbook = $parser->parse($self->{input_file});
my $worksheet = $workbook->worksheet(0);
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
my $name;
my @chunks;
$self->save_header_line( $worksheet, $row_min );
$row_min++;
for my $row ( $row_min .. $row_max ) {
my $col0 = 0;
my $cell0 = $worksheet->get_cell( $row, $col0 );
if (!$cell0) {
push @chunks, $name if defined $name;
$name = undef;
next;
}
my $col3 = 3;
my $cell3 = $worksheet->get_cell( $row, $col3 );
if ($cell3) {
$name = $cell3->unformatted();
($name) = $name =~ /^(\S+)/;
}
}
push @chunks, $name if defined $name;
$self->{chunks} = \@chunks;
}
sub save_header_line {
my ( $self, $worksheet, $row_min ) = @_;
my ( $col_min, $col_max ) = $worksheet->col_range();
my %skip = map { $_ => 1 } @{$self->{skip_cols}};
my @header;
my $row0 = 0;
my %col_map;
my $new_col = 0;
for my $col ( $col_min .. $col_max ) {
next if exists $skip{$col};
$col_map{$col} = $new_col;
$new_col++;
my $cell = $worksheet->get_cell( $row0, $col );
push @header, $cell;
}
$self->{header} = \@header;
$self->{skip_col} = \%skip;
$self->{col_map} = \%col_map;
}
sub start_new_chunk {
my ( $self, $name) = @_;
say "--> $name.xlsx";
$self->close_chunk_file();
$self->{workbook} = Excel::Writer::XLSX->new( "$name.xlsx" );
$self->{worksheet} = $self->{workbook}->add_worksheet();
$self->write_header();
}
sub write_cell {
my ( $self, $row, $col, $cell) = @_;
my $fmt = $cell->get_format();
my $fmt_props = translate_xlsx_format( $fmt );
my $new_format = $self->{workbook}->add_format(%$fmt_props);
my $value = $cell->unformatted() || '';
$self->{worksheet}->write($row, $self->{col_map}{$col}, $value, $new_format);
}
sub write_chunks {
my ( $self ) = @_;
my $parser = Spreadsheet::ParseXLSX->new;
my $workbook = $parser->parse($self->{input_file});
my $worksheet = $workbook->worksheet(0);
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
my @chunks = @{$self->{chunks}};
die "No chunks to write\n" if @chunks == 0;
$self->start_new_chunk(shift @chunks);
my $chunk_row = 1; # skip header row
$row_min++; # skip header row
ROW: for my $row ( $row_min .. $row_max ) {
for my $col ( $col_min .. $col_max ) {
my $cell = $worksheet->get_cell( $row, $col );
if ( $col == 0 && !$cell) {
if (@chunks) {
$self->start_new_chunk(shift @chunks);
$chunk_row = 1;
next ROW;
}
else {
last;
}
}
if ( $cell ) {
if (!exists $self->{skip_col}{$col}) {
$self->write_cell($chunk_row, $col, $cell);
}
}
}
$chunk_row++;
}
$self->close_chunk_file();
}
sub write_header {
my ( $self ) = @_;
my $header = $self->{header};
for my $col ( 0 .. $#$header ) {
my $cell = $header->[$col];
next if !$cell;
my $fmt = $cell->get_format();
my $fmt_props = translate_xlsx_format( $fmt );
my $new_format = $self->{workbook}->add_format(%$fmt_props);
my $value = $cell->unformatted() || '';
my $row0 = 0;
$self->{worksheet}->write($row0, $col, $value, $new_format);
}
}