免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 7522 | 回复: 5
打印 上一主题 下一主题

excel2csv.pl(excel文件到csv文件转换脚本) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-18 21:53 |只看该作者 |倒序浏览
网上大多数的excel文件转换的perl脚本是用的Spreadsheet::ParseExcel::FmtUnicode和Unicode::Map来支持含有中文excel转换的。
但是这样做有个缺点,就是用PDK打包之后就不能正确转换了,会变成乱码。
下面的脚本可以避免这个问题。
注意: Spreadsheet::ParseExcel默认使用是Spreadsheet::ParseExcel::FmtDefault.pm来做格式解码。而为了excel2csv.pl能支持中文, 你必须把FmtDefault.pm中的
  1. sub TextFmt($$;$)
复制代码
过程的返回值那一行(第68行)的
  1. return pack('C*', unpack('n*', $sTxt));
复制代码
改为
  1. return pack('U*', unpack('n*', $sTxt));
复制代码
如果你熟悉pack的使用那这个改动的意义是不言自明的。
好了,以下是脚本

  1. #!/usr/bin/perl -W
  2. #
  3. # File: excel2csv.pl
  4. # Author: 路小佳
  5. # License: GPL-2

  6. use strict;
  7. use warnings;

  8. use Spreadsheet::ParseExcel;
  9. use Encode;
  10. our $local_enc = 'cp936';

  11. sub decode_cell($)
  12. {
  13.     my $cell = shift;
  14.     if (!$cell) {
  15.         return '';
  16.     }
  17.     if ($cell->{Type} eq 'Text' && defined($cell->{Code})) {
  18.         if ($cell->{Code} eq 'ucs2') {
  19.             $cell->{Val} = decode('UTF16-BE', $cell->{Val});
  20.         }
  21.         elsif ($cell->{Code} eq '_native_') {
  22.             $cell->{Val} = decode($local_enc, $cell->{Val});
  23.         }
  24.     }
  25.     elsif ($cell->{Type} eq 'Date') {
  26.         #TODO
  27.     }
  28.     elsif ($cell->{Type} eq 'Number') {
  29.         #TODO
  30.     }
  31.     return $cell->{Val};
  32. }

  33. sub excel2csv($) {
  34.     my $file = shift;
  35.     my $book = Spreadsheet::ParseExcel::Workbook->Parse($file);
  36.     if (!$book) {
  37.         warn "Cannot Parse $file: $!\n";
  38.         return undef;
  39.     }
  40.     $file =~ s/\.xls$//i;
  41.     foreach my $sheet (@{$book->{Worksheet}}) {
  42.         my $name = $file.'_'.encode($local_enc, $sheet->{Name});
  43.         print "sheet \"$name\" is parsing...\n";
  44.         local *FH;
  45.         if (!open(FH, ">$name.csv")) {
  46.             warn "Cannot write $name.csv: $!";
  47.             next;
  48.         }
  49.         my ($i, $line);
  50.         foreach $i ($sheet->{MinRow}..$sheet->{MaxRow}) {
  51.             $sheet->{MaxCol} ||= $sheet->{MinCol};
  52.             $line = join(',', map {encode('utf8', decode_cell($sheet->{Cells}[$i][$_]))} ($sheet->{MinCol}..$sheet->{MaxCol}));
  53.             if ($line =~ m/^,*$/) {
  54.                 $line = '';
  55.             }
  56.             print FH $line."\n";
  57.         }
  58.         close(FH);
  59.     }
  60. }

  61. foreach (<*.xls>) {
  62.     print "parsing $_ ...\n";
  63.     excel2csv($_);
  64. }
复制代码

补充一下, 一般的excel的单元格有Text,Date,Value三种形式,Date,Value是以浮点存储的, 可以直接返回,Text的话在$cell->{Code}会指明编码方式ucs2(UTF61_BE), _native_, ascii. 而excel的工作簿的名字是以wide char形式存储的, 读取后直接encode即可。

[ 本帖最后由 路小佳 于 2007-3-18 21:55 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-03-18 22:07 |只看该作者
刚才心血来潮, 到网上一搜"excel2csv", 结果发现已有了一个vbs的实现了。:(
http://www.vector.co.jp/soft/win95/business/se259639.html
嗯,日本人很厉害。Spreadsheet::ParseExcel是日本写的, excel2csv.vbs也是的。

论坛徽章:
0
3 [报告]
发表于 2007-03-19 11:54 |只看该作者
hehe
我见过日本人用VBS生成了对数据库表的自动excel转成sql建表和索引的语句
并且都把每个表做成了单独的模块,用对象方法来操作,obj->select,obj->update,obj->delete

论坛徽章:
0
4 [报告]
发表于 2007-03-19 12:07 |只看该作者
日本人玩excel很厉害的
拿excel当photoshop了,各种设计和design方案,项目流程图写的那个精致。。。。
佩服的五体投地。。。。

论坛徽章:
0
5 [报告]
发表于 2007-03-19 12:33 |只看该作者
支持搂住,知识共享。

论坛徽章:
0
6 [报告]
发表于 2007-03-19 13:50 |只看该作者
同样支持
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP