车皮 发表于 2018-8-31 13:25:50

Perl的Excel读写问题

  老有人问我 excel 中文乱码的问题,
  
我平时很少接触这一块,
  
每次都得从头研究,
  
现在把结论记录在这里,以做备忘。
  

  
读:
  


[*]use strict;
[*]use warnings;
[*]
[*]use Spreadsheet::ParseExcel;
[*]use MyExcelFormatter;
[*]
[*]my $file = 'foo.xls';
[*]
[*]my $fmt = new MyExcelFormatter();
[*]
[*]my $xls = Spreadsheet::ParseExcel::Workbook->Parse( $file, $fmt );
[*]my @workSheet = @{ $xls->{Worksheet} };
[*]foreach my $sheet ( @workSheet ){
[*]    my $sheetName = $sheet->get_name();
[*]    print "工作表: $sheetName\n";
[*]
[*]    my ( $minRow, $maxRow ) = $sheet->row_range();
[*]    my ( $minCol, $maxCol ) = $sheet->col_range();
[*]
[*]    foreach my $row ( $minRow .. $maxRow ){
[*]      foreach my $col ( $minCol .. $maxCol ){
[*]            my $cell = $sheet->get_cell( $row, $col );
[*]            next unless $cell;
[*]            print " ($row,$col) ", $cell->value;
[*]      }
[*]      print "\n";
[*]    }
[*]}
  

  基本上上面这段代码就是从 Spreadsheet::ParseExcel 的文档里抄来的。
  
除了 my $fmt = new MyExcelFormatter(); 这一行之外。
  
这一行生成了一个文档内容的转换器(格式化工具),
  
转换器代码如下:
  


[*]package MyExcelFormatter;
[*]
[*]use strict;
[*]use warnings;
[*]
[*]use base qw(Spreadsheet::ParseExcel::FmtDefault);
[*]
[*]use Encode::CN;
[*]use Encode qw(from_to);
[*]
[*]sub new() {
[*]    return bless {};
[*]}
[*]
[*]sub TextFmt( $;$ ) {
[*]    my $this = shift;
[*]    my ($value, $code) = @_;
[*]
[*]    if ( defined $code and $code eq 'ucs2' ){
[*]      from_to( $value, 'ucs2', 'gb2312' );
[*]    }
[*]    return $value;
[*]}
[*]
  

  如法炮制以此类推,可以处理所有本地语言编码。
  

  
写 excel,这个就更简单了:
  


[*]use strict;
[*]use warnings;
[*]
[*]use Spreadsheet::WriteExcel;
[*]
[*]my $workbook = new Spreadsheet::WriteExcel( 'foo.xls' );
[*]my $worksheet = $workbook->add_worksheet( T('世界你好') );
[*]
[*]$worksheet->write( 0, 0, T('干啥呢') );
  

  大家可以看到,完全就是抄 perldoc 文档里的例子的。
  
只不过,T( '世界你好' ) 看上去有点怪怪的罢了。
  
其实这是一个自定义函数:
  


[*]use Encode qw(decode);
[*]
[*]sub T {
[*]    my $text = shift;
[*]
[*]    return decode( 'gb2312', $text );
[*]}
  

  名字当然也可以不叫 T,叫别的也行。
  
完整的代码如下:
  


[*]use strict;
[*]use warnings;
[*]
[*]use Spreadsheet::WriteExcel;
[*]use Encode qw(decode);
[*]
[*]my $workbook = new Spreadsheet::WriteExcel( 'foo.xls' );
[*]my $worksheet = $workbook->add_worksheet( T('世界你好') );
[*]
[*]$worksheet->write( 0, 0, T('干啥呢') );
[*]
[*]sub T {
[*]    my $text = shift;
[*]
[*]    return decode( 'gb2312', $text );
[*]}
  

  最后再来个总结:
  
要点只有一个:excel 里保存的是且只能是 utf8 编码,而简体中文版的 windows 控制台和其它一些软件缺省显示的是 gb2312 编码
  
有些朋友在 tk 应用或者 mysql 应用中用了上面的代码,仍然看到乱码,那是因为你没有搞明白 tk 和 mysql 的编码,所以上面的办法也不是万能的。
  
万能的办法就是搞清楚每个信息流的编码方案,彻底把思路搞明白了。


页: [1]
查看完整版本: Perl的Excel读写问题