- 论坛徽章:
- 0
|
网上大多数的excel文件转换的perl脚本是用的Spreadsheet::ParseExcel::FmtUnicode和Unicode::Map来支持含有中文excel转换的。
但是这样做有个缺点,就是用PDK打包之后就不能正确转换了,会变成乱码。
下面的脚本可以避免这个问题。
注意: Spreadsheet::ParseExcel默认使用是Spreadsheet::ParseExcel::FmtDefault.pm来做格式解码。而为了excel2csv.pl能支持中文, 你必须把FmtDefault.pm中的过程的返回值那一行(第68行)的- return pack('C*', unpack('n*', $sTxt));
复制代码 改为- return pack('U*', unpack('n*', $sTxt));
复制代码 如果你熟悉pack的使用那这个改动的意义是不言自明的。
好了,以下是脚本
- #!/usr/bin/perl -W
- #
- # File: excel2csv.pl
- # Author: 路小佳
- # License: GPL-2
- use strict;
- use warnings;
- use Spreadsheet::ParseExcel;
- use Encode;
- our $local_enc = 'cp936';
- sub decode_cell($)
- {
- my $cell = shift;
- if (!$cell) {
- return '';
- }
- if ($cell->{Type} eq 'Text' && defined($cell->{Code})) {
- if ($cell->{Code} eq 'ucs2') {
- $cell->{Val} = decode('UTF16-BE', $cell->{Val});
- }
- elsif ($cell->{Code} eq '_native_') {
- $cell->{Val} = decode($local_enc, $cell->{Val});
- }
- }
- elsif ($cell->{Type} eq 'Date') {
- #TODO
- }
- elsif ($cell->{Type} eq 'Number') {
- #TODO
- }
- return $cell->{Val};
- }
- sub excel2csv($) {
- my $file = shift;
- my $book = Spreadsheet::ParseExcel::Workbook->Parse($file);
- if (!$book) {
- warn "Cannot Parse $file: $!\n";
- return undef;
- }
- $file =~ s/\.xls$//i;
- foreach my $sheet (@{$book->{Worksheet}}) {
- my $name = $file.'_'.encode($local_enc, $sheet->{Name});
- print "sheet \"$name\" is parsing...\n";
- local *FH;
- if (!open(FH, ">$name.csv")) {
- warn "Cannot write $name.csv: $!";
- next;
- }
- my ($i, $line);
- foreach $i ($sheet->{MinRow}..$sheet->{MaxRow}) {
- $sheet->{MaxCol} ||= $sheet->{MinCol};
- $line = join(',', map {encode('utf8', decode_cell($sheet->{Cells}[$i][$_]))} ($sheet->{MinCol}..$sheet->{MaxCol}));
- if ($line =~ m/^,*$/) {
- $line = '';
- }
- print FH $line."\n";
- }
- close(FH);
- }
- }
- foreach (<*.xls>) {
- print "parsing $_ ...\n";
- excel2csv($_);
- }
复制代码
补充一下, 一般的excel的单元格有Text,Date,Value三种形式,Date,Value是以浮点存储的, 可以直接返回,Text的话在$cell->{Code}会指明编码方式ucs2(UTF61_BE), _native_, ascii. 而excel的工作簿的名字是以wide char形式存储的, 读取后直接encode即可。
[ 本帖最后由 路小佳 于 2007-3-18 21:55 编辑 ] |
|