【问题标题】:Parse Excel data raises "File error"解析 Excel 数据引发“文件错误”
【发布时间】:2019-01-16 22:39:07
【问题描述】:

我在 Perl 脚本中有三个函数来解析 Excel 文件以获取所需的输出 Excel 文件。我得到了正确的输出,但是我得到一个错误

文件错误:数据可能已丢失

可能根本原因是在文件中两次写入同一个 Excel 单元格。

如何在维护脚本中的功能的同时消除此错误?

输入文件

  A             B
Apples       Carrots
Oranges      Broccoli
Grapes       Spinach

想要的输出文件

  A             B
Apples       Carrots
Oranges      Broccoli
PEACHES      ASPARAGUS

Perl 代码

use v5.10.0;
use warnings;

use Spreadsheet::ParseExcel;
use Spreadsheet::ParseExcel::SaveParser;
use Spreadsheet::WriteExcel;

my $parser     = Spreadsheet::ParseExcel::SaveParser->new();
my $workbook_R = $parser->parse('C:\Perl\databases\Fruits_and_Veggies.xls');

my $workbook_W  = Spreadsheet::WriteExcel->new('C:\Perl\databases\New_Fruits_and_Veggies.xls');
my $worksheet_W = $workbook_W->add_worksheet();

for our $worksheet_R ( $workbook_R->worksheets() ) {

    my ( $row_min, $row_max ) = $worksheet_R->row_range();
    my ( $col_min, $col_max ) = $worksheet_R->col_range(); 

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

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

            FruitStand();

            VeggieStand();

            ComboStand();


            #------------------------------------------------------------------------------
            # sub FruitStand - parsing: replace Grapes with PEACHES
            #------------------------------------------------------------------------------

            sub FruitStand {

                # if the cell contains Grapes write 'PEACHES' instead
                my $cell_grapes = $worksheet_R->get_cell( $row, $col );

                if ( $cell_grapes->value() =~ /Grapes/ ) {
                    $worksheet_W->write($row, $col,"PEACHES");
                }
            }


            #------------------------------------------------------------------------------
            # sub VeggieStand - parsing: repalce Spinach with ASPARAGUS
            #------------------------------------------------------------------------------

            sub VeggieStand {

                # if the cell contains Spinach write 'ASPARAGUS' instead
                my $cell_veggies = $worksheet_R->get_cell( $row, $col );
                # my $cell = $worksheet_R->get_cell( $row, $col );

                if (/ $cell_veggies->value() =~ /Spinach/ ) {
                    $worksheet_W->write($row, $col,"ASPARAGUS");
                }
            }

            #------------------------------------------------------------------------------
            # Writing all fruits and veggies with the 2 changes (PEACHES and ASPARAGUS)
            #------------------------------------------------------------------------------

            sub ComboStand {

                my $cell = $worksheet_R->get_cell( $row, $col );
                $worksheet_W->write($row, $col, $cell->value()) ;
            }
        }
    }
}

【问题讨论】:

  • 错误来自同一来源(一个单元格被多次写入)-我了解您想要消除错误并询问如何做到这一点。 “可能重复”将帮助遇到相同错误的其他人查看其他相关帖子。
  • 好的。尽我所能。
  • @user1608954:请不要这么快就拒绝您要求的帮助。链接的问题看起来和我一模一样。

标签: excel perl


【解决方案1】:

正如您所说,错误消息是由于一个单元格被多次写入。您可以通过确保每个单元格只写入一次来消除错误消息。由于您的三个子例程具有非常相似的功能,因此可以将它们组合成一组可以执行所有操作的行,并使用 if / else 级联来决定应采取的操作。

for our $row ( $row_min .. $row_max ) {
  for our $col ( $col_min .. $col_max ) {

    my $cell = $worksheet_R->get_cell( $row, $col );
    if($cell->value() =~ /Spinach/) {
      $worksheet_W->write($row, $col,"ASPARAGUS");
    }
    elsif($cell->value() =~ /Grapes/) {
      $worksheet_W->write($row, $col,"PEACHES");
    }
    else {
      $worksheet_W->write($row, $col, $cell->value()) ;
    }
  }
}

如果你必须保留这些函数,我建议像这样,你有一个函数可以获取当前单元格并对其应用任何适当的转换,并返回准备好输出的文本。这样可以避免重复读取单元格和写入单元格的子程序:

for our $row ( $row_min .. $row_max ) {
  for our $col ( $col_min .. $col_max ) {
    my $cell = $worksheet_R->get_cell( $row, $col );
    $worksheet_w->write( $row, $col, produce_check($cell->value) );
  }
}

并且执行交换的produce_check 子也将是进行任何文本规范化或您可能想要对输入进行的其他检查的好地方,例如删除多余的空格,将所有输出设置为标题大小写等。

sub produce_check {
  my $prod = shift;
  # maybe we have to make sure there's no trailing whitespace on $prod
  $prod =~ s/\s*$//;
  my %swaps = (
    grapes => 'peaches',
    spinach => 'asparagus',
    tins => 'cans',
    zuchini => 'zucchini'
  );
  # is $prod one of pieces of produce we have to swap?
  # perhaps our input is in a mixture of cases, uppercase, lowercase, titlecase
  # to avoid having to add all those variations to the %swaps hash, we convert
  # to lowercase using `lc`
  if ( $swaps{ lc($prod) } ) {
    $prod = $swaps{ lc($prod) };
  }
  # this line uses `ucfirst($prod)` to convert all output to titlecase.
  # You could also convert everything to lowercase ( `lc($prod)` ), to
  # uppercase ( `uc($prod)` ), or just leave it as-is by using `return $prod;`
  return ucfirst( $prod );
}

【讨论】:

  • 谢谢“我惊动了外星人。”但我需要保留我的功能,以便它是模块化的,我可以在此基础上进行构建。
  • 有没有办法在保留功能的同时解决?
  • 是的——但是对于这种脚本来说,具有单独的文本替换功能有点 OTT。良好编码的其他原则之一是“不要重复自己”,并且具有三个执行非常相似的事情的功能(读取单元格内容,可能交换单词,写入单元格内容)将违反该原则。
  • 我只是在考虑数据库的增长。如果我有一个巨大的excel文件怎么办?函数会是处理 if/elsif/else 的更好方法吗?我在考虑模块化。
  • 一天后,还在想这个绝妙的解决方案,把函数放在$worksheet_w->write里面。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 1970-01-01
  • 2021-12-15
  • 1970-01-01
  • 2019-04-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多