Chinaunix首页 | 论坛 | 博客
  • 博客访问: 225702
  • 博文数量: 36
  • 博客积分: 1188
  • 博客等级: 军士长
  • 技术积分: 802
  • 用 户 组: 普通用户
  • 注册时间: 2010-04-08 21:45
文章分类

全部博文(36)

文章存档

2020年(1)

2017年(2)

2015年(1)

2014年(1)

2013年(1)

2012年(3)

2011年(27)

分类: WINDOWS

2011-03-24 16:40:57

有兴趣学习perl数据结构的构造、解析和Moo***::Declare的入门初学者,可参考本文代码。
 
    医院经常得业务查房与行政查房,每次检查都会以科室为单位记录发现的问题,但往往检查发现问题的科室并不一定是都是整改责任科室(有时候会出现一个问题的整改需几个科室共同承担责任),而且检查记录是由几个人共同完成的,加上医院科室很多,所以每次要根据责任科室重新整理改进项目时,都要花大量的时间。为了方便完成此项工作,先是用VBA写了代码,后来又转为Perl代码了。为了学习perl的OO于是将代码用Moo***::Declare进行了改写。终于不会过段时间连自已也看不懂代码了。
一、
    以上问题的描述转化为:将几份word文档内的所有表格每行的内容按责任人进行归类整理。
如下图的第二个表的"我/你们"得归类到"我"与"你们"两类。
二、以下是代码及附件: 附件.rar   
附件包括测试用的word文档、perl代码。要是在博客上不好看就下附件吧,内附POD
  1. #############################################################################

  2. ## Name: MD.pl

  3. ## Purpose: 因受美女管理员邀请,盛意难却,参加CU的征文大赛。将以前工作

  4. ## 用到的代码转为Moo***::Declare的oo形式。^_^

  5. ## Author: aef25u

  6. ## Created: 3/24/2011

  7. ## RCS-ID:

  8. ## Copyright: (c) 2011 Maef25u

  9. ## Licence: This program is free software; you can redistribute it and/or

  10. ## modify it under the same terms as Perl itself

  11. #############################################################################

  12. use Cwd;
  13. use Win32::OLE;
  14. use Moo***::Declare;

  15. #use Data::Dumper;

  16. #############################################################################

  17. class SearchFile {
  18.     has regex =>
  19.       ( is => 'rw', isa => 'Str', required => 1, default => '.*\.doc$' );

  20.     #弹出窗口,以供选择目标文件夹

  21.     method _Path {
  22.         my $shell = Win32::OLE->new("shell.Application");
  23.         my $objFolder = $shell->BrowseForFolder( 0, "Select a folder:", 0 );
  24.         my $Path = $objFolder->Self->{Path};
  25.         $Path =~ s/(\\)/\//g;
  26.         return $Path;
  27.     }

  28.     #遍历搜索文件,支持正则表达式

  29.     method File_Find {
  30.         my $tem = $self->regex;
  31.         my $qr_regex = qr/$tem/;
  32.         my $Path = $self->_Path();
  33.         my @dirs = ( $Path . '/' );
  34.         my ( @retFile, $dir, $file );
  35.         while ( $dir = pop(@dirs) ) {
  36.             local *DH;
  37.             if ( !opendir( DH, $dir ) ) {
  38.                 warn "Cannot opendir $dir: $! $^E";
  39.                 next;
  40.             }
  41.             foreach ( readdir(DH) ) {
  42.                 if ( $_ eq '.' || $_ eq '..' ) {
  43.                     next;
  44.                 }
  45.                 $file = $dir . $_;
  46.                 if ( $file =~ /$qr_regex/ ) {
  47.                     push( @retFile, $file );
  48.                 }
  49.                 if ( !-l $file && -d _ ) {
  50.                     $file .= '/';
  51.                     push( @dirs, $file );
  52.                 }
  53.             }
  54.             closedir(DH);
  55.         }
  56.         return \@retFile;
  57.     }

  58. }
  59. #############################################################################

  60. #my $objFind=SearchFile->new(regex=>'.*\.xls');

  61. #my $objFind=SearchFile->new();

  62. #my $ffn=$objFind->File_Find();

  63. #print join("\n",@{$ffn});

  64. #############################################################################


  65. class WordOLE {
  66.     has Doc => ( is => 'rw', isa => 'Win32::OLE' );

  67.     #提取word文档所有表格某一列单元格字符串,以“/”折分字符串并返回唯一子串

  68.     method Sear_Cell_Uni( Num $Cell_col) {
  69.         my $qr_regex = qr/\//;
  70.           my @reStr;
  71.           my $tCount = $self->Doc->Tables->{'Count'};

  72.           foreach my $i ( 1 .. $tCount ) {
  73.             my $table = $self->Doc->Tables($i);
  74.             my $rNum = $table->Rows->{Count};

  75.             foreach my $j ( 2 .. $rNum ) {
  76.                 my $Cell = $table->Cell( $j, $Cell_col )->Range->{Text};
  77.                 $Cell =~ s/([(\r\r)(\n\n)(\r\n)])//g;
  78.                 chop($Cell);
  79.                 if ( $Cell =~ m/$qr_regex/ ) {
  80.                     my @temp = split( "$qr_regex", $Cell );
  81.                     push( @reStr, @temp );
  82.                 }
  83.                 else {
  84.                     push( @reStr, $Cell );
  85.                 }
  86.             }
  87.         }
  88.         return $self->_Unique( \@reStr );

  89.       }

  90. #“关键字”与“指定表格某一列所有单元格”进行匹配,将表格的整行内容按“关键字”进行归类

  91.       method Re_Mat_Row( ArrayRef [Str] $keys, Num $Cell_col) {
  92.         my %reStr;
  93.           my $tCount = $self->Doc->Tables->{'Count'};

  94.           foreach my $key ( @{$keys} ) {
  95.             @{ $reStr{$key} } = ();
  96.             foreach my $i ( 1 .. $tCount ) {
  97.                 my $table = $self->Doc->Tables($i);
  98.                 my $rNum = $table->Rows->{Count};

  99.                 foreach my $j ( 2 .. $rNum ) {
  100.                     my $Cell = $table->Cell( $j, $Cell_col )->Range->{Text};
  101.                     $Cell =~ s/([(\r\r)(\n\n)(\r\n)])//g;
  102.                     chop($Cell);
  103.                     if ( $Cell =~ m/$key/ ) {
  104.                         my @temp;
  105.                         my $c_Count = $table->Rows($j)->Cells->{Count};
  106.                         foreach ( 1 .. $c_Count ) {
  107.                             my $txt = $table->Cell( $j, $_ )->Range->{Text};
  108.                             chop($txt);
  109.                             push( @temp, $txt );
  110.                         }
  111.                         push( @{ $reStr{$key} }, \@temp );

  112.                     }
  113.                 }
  114.             }
  115.         }
  116.         return \%reStr;

  117.       }

  118.       #将数组元素过滤为唯一值

  119.       method _Unique( ArrayRef [Str] $tem ) {
  120.         my %hash;
  121.           foreach ( @{$tem} ) {
  122.             $hash{$_}++;
  123.         }
  124.         my @elem_Uni = sort keys %hash;
  125.           return \@elem_Uni;
  126.       }

  127. }
  128. #############################################################################

  129. #my $word = Win32::OLE->new("Word.Application");

  130. #$word->{Visible} = 1;

  131. #my $document = $word->documents->Open('G:/结果/a.doc');

  132. #my $obj = WordOLE->new( Doc => $document );

  133. #my $arr = $obj->Sear_Cell_Uni(4);

  134. #my $brr = $obj->Re_Mat_Row( $arr, 4 );

  135. #print Dumper($brr);

  136. #$document->close;

  137. #$word->quit;

  138. #############################################################################



  139. # Main program

  140. my $dir = getcwd();
  141. my $BookName = $dir . '/整理结果.xls';

  142. #添加Word.Application obj

  143. my $word = Win32::OLE->new("Word.Application");
  144. $word->{Visible} = 1;

  145. #搜索doc文件,new的参数默认为{regexqr=>/.*\.doc$/}

  146. my $objFind = SearchFile->new();
  147. my $ffn = $objFind->File_Find();

  148. #添加Excel.Application obj

  149. my $Excel = Win32::OLE->new("Excel.Application");
  150. $Excel->{Visible} = 1;
  151. $Excel->{SheetsInNewWorkBook} = 1;
  152. my $Book = $Excel->Workbooks->Add;
  153. $Book->SaveAs( { Filename => $BookName } );

  154. #遍历打开文件进行处理

  155. my ( $Sear_key, @Sear_temp, @mat_arr );

  156. foreach my $file ( @{$ffn} ) {
  157.     my $document = $word->documents->Open($file);
  158.     my $obj = WordOLE->new( Doc => $document );
  159.     my $temp = $obj->Sear_Cell_Uni(4);
  160.     push( @Sear_temp, @{$temp} );
  161.     $Sear_key = $obj->_Unique( \@Sear_temp );
  162.     $document->close;
  163. }

  164. #print Dumper($Sear_key);


  165. foreach my $file ( @{$ffn} ) {
  166.     my $document = $word->documents->Open($file);
  167.     my $obj = WordOLE->new( Doc => $document );
  168.     my $temp = $obj->Re_Mat_Row( $Sear_key, 4 );
  169.     push( @mat_arr, $temp );
  170.     $document->close;
  171. }

  172. #print Dumper(\@mat_arr);


  173. #解析数据结构@mat_arr,将数据写进Excel

  174. foreach my $re_match (@mat_arr) {
  175.     foreach my $key ( keys %{$re_match} ) {

  176.         #print Dumper($re_match->{$key});

  177.         my $Row_Count = @{ $re_match->{$key} };

  178.         my $Sheet_Name = $Book->ActiveSheet->{Name};

  179.        #检查是否存在以$key命名的工作表,无则新建并写入内容,有则往后一行增加内空

  180.         if ( !$Book->Sheets($key) ) {
  181.             $Book->Sheets->Add;
  182.             $Book->ActiveSheet->{Name} = $key;
  183.             my $ActSheet = $Book->ActiveSheet;
  184.             $ActSheet->Range('A1:E1')->{'Value'} =
  185.               [ [ '存在问题', '原因分析', '整改要求', '责任人', '关闭时间' ] ];
  186.             my $MaxRows = $ActSheet->UsedRange->Rows->{Count};
  187.             my $RowHight = $MaxRows + $Row_Count;
  188.             $ActSheet->Range( 'A2:E' . $RowHight )->{'Value'} =
  189.               $re_match->{$key};
  190.         }
  191.         else {
  192.             $Book->Sheets($key)->Select;
  193.             my $ActSheet = $Book->ActiveSheet;
  194.             $Book->Sheets($key)->Range('A1:E1')->{'Value'} =
  195.               [ [ '存在问题', '原因分析', '整改要求', '责任人', '关闭时间' ] ];
  196.             my $MaxRows = $ActSheet->UsedRange->Rows->{Count};
  197.             my $RowHight = $MaxRows + $Row_Count;
  198.             my $Star_Row = $MaxRows + 1;
  199.             $ActSheet->Range( 'A' . $Star_Row . ':E' . $RowHight )->{'Value'} =
  200.               $re_match->{$key};
  201.         }
  202.     }
  203. }
  204. $Book->save;
  205. $Book->close;

  206. $word->quit;
  207. $Excel->quit;
三、简单介绍:
作用:弹出窗口,以供选择目标文件夹,按指定的正则模式搜索文件,并返回搜索到的所有文件数组的引用。

设定正则模式:regex=>'Regex',默认为'.*\.doc$'

支持正则表达式,遍历搜索文件夹匹配的文件,将返回所有文件数组的引用。 调用内置方法_Path()。

  1. my $objFind=SearchFile->new(regex=>'.*\.xls');#更改正则匹配模式

  2.  #my $objFind=SearchFile->new(); #缺省参数时:regex=>'.*\.doc$'

  3.  my $ffn=$objFind->File_Find();
  4.  print join("\n",@{$ffn});

作用:1、Sear_Cell_Uni()方法,提取word文档所有表格某一列单元格字符串,以“/”折分字符串并返回唯一子串Array的引用; 2、Re_Mat_Row(),“关键字”与“指定表格某一列所有单元格”进行匹配,将表格的整行内容按“关键字”进行归类,返回 一个Hash的引用。

Win32::OLE->new("Word.Application")对象的引用。

使用:$obj->Sear_Cell_Uni(查找表格第几列) 调用内置方法_Unique()。

使用:$obj->Re_Mat_Row(关键字,与表格第几列进行匹配)

  1. my $word = Win32::OLE->new("Word.Application");
  2.  $word->{Visible} = 1;
  3.  my $document = $word->documents->Open('G:/结果/a.doc');
  4.  my $obj = WordOLE->new( Doc => $document );
  5.  my $arr = $obj->Sear_Cell_Uni(4);
  6.  my $brr = $obj->Re_Mat_Row( $arr, 4 );
  7.  print Dumper($brr);
  8.  $document->close;
  9.  $word->quit;

四、Main program的工作流程
4.1生成关键字
(1)、my $temp     = $obj->Sear_Cell_Uni(4);
 一份份打开文件生成唯一关键字的Array的引用。
(2)、push( @Sear_temp, @{$temp} );
每打开一份文件,将生成了唯一关键字的数组push进@Sear_temp。
(3)、$Sear_key = $obj->_Unique( \@Sear_temp );
所有文件打开后,调用_Unique()将@Sear_temp过滤为唯一元素数组。
4.2构造数据结构
(1)、my $temp     = $obj->Re_Mat_Row( $Sear_key, 4 );
一份份打开文件,每打开一份文件按$Sear_key将表格的内容行进行归类,生成$temp={$Sear_key=>[[],...]}。
(2)、push( @mat_arr, $temp );
每打开一份文件,将$temp散列引用push进@mat_arr。
4.3解析数据结构,写入数据

获奖了,CU寄来了个无线鼠标,拍了张照片

阅读(8178) | 评论(5) | 转发(1) |
给主人留下些什么吧!~~

aef25u2011-04-27 22:22:33

2gua: 同样是一篇操作Office文档的文章,阐述得很具体,作者对OO也有一定理解,文章实用性强,注释良好。.....
感谢评委的鼓励

2gua2011-04-26 10:12:23

同样是一篇操作Office文档的文章,阐述得很具体,作者对OO也有一定理解,文章实用性强,注释良好。

aef25u2011-03-26 09:37:22

没想到第一次写博文就被置顶至CU博客首页了。^_^

aef25u2011-03-24 17:34:28

小雅贝贝: 很好的文章呢~~
谢谢支持本次活动~~
希望以后多多写博文~~.....
我刚发完,就有美女过来踩

小雅贝贝2011-03-24 17:25:32

很好的文章呢~~
谢谢支持本次活动~~
希望以后多多写博文~~