Thread excelPerl
(15 answers)
Opened by
Strat
at 2006-11-05 23:06
User since 2003-08-04
5246
Artikel
ModeratorIn
Eine neue Version ist fertig:
xlsPerl.pl
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
#! /usr/bin/perl use warnings; use strict;
use Getopt::Long; use File::Basename; use XlsPerl;
$|++; # no suffering from buffering
my( $file, $perlCode ); my $worksheetNumber = 1; my $headline = 0; my $visible = 0; my $colSeparator = "\t";
GetOptions( 'file=s' => \$file, 'sheet=i' => \$worksheetNumber, 'headline=i' => \$headline, 'ane=s' => \$perlCode, 'visible' => \$visible, 'colseparator' => \$colSeparator, ) or die &PrintUsage();
my $xlsPerl = XlsPerl->new( excelFile => $file, worksheetNumber => $worksheetNumber, ) ->open;
#if( $visible ) { $xlsPerl->excel->{Visible} = 1; #} # if
# skip all lines until -headline if available $xlsPerl->currentRow( $headline ) if $headline;
# TODO: the global @F is dirty... use a better way, e.g. with alias use vars qw(@F); while( $xlsPerl->getNextRow ) { my $R = $xlsPerl->currentRow(); local $_ = join($colSeparator, @F ) . "\n";
eval $perlCode; die $@ if $@;
} # while
# ------------------------------------------------------------ sub PrintUsage {
my $bin = File::Basename::basename($0); die <<EOH; $bin -file filename -sheet 1 -headline 1 -visible
try perldoc $bin for more details
EOH
} # PrintUsage # ------------------------------------------------------------
=pod
=head1 xlsPerl
You know about the perl parameters -ane? This script is a way to try to do the same thing to Excel files. But although working somehow, it isn't finished.
=head1 Prerequisites
=over 1
=item Win32::OLE
=item Excel needs to be installed
=back
=head1 Description
This script xlsPerl.pl loops over an excel file row by row (like perl -ne). It splits the cells into an array with name @F (like perl -ane), and executes a given bit of perl code for each row.
If you modify elements of @F, you modify the excel cell the value comes from. Beware: this feature is still very experimental
=head1 Params:
-file String: Name of excel file (full path) # -visible Boolean: make excel visible (funny, but not yet useful) -sheetnumber Integer: which sheet shell I read (1..n, default: 1) -headline Integer: line number of headline (used for skipping headline) -ane String: Perl-Code to execute -colseparator String: how to join columns in $_ (default: \t)
Abbreviations of params are allowed, as long as they are unique, e.g
xlsPerl.pl -s 2 -m 10 -ane "print qq~$R: $F[0] $F[5]\n" -f c:\test.xls
=head1 Special Variables:
$R Row number @F Array containing the values of one complete row $_ Row joined by -colseparator, with \n at the end
=head1 Bugs/...
This code is very, very, very experimental, and some parts are dirty!
If you do changes, you have to save the workbook by yourself, that's the reason why the parameter -visible always is on.
=head1 Author
Martin Fabiani L<http://www.fabiani.net/>
=cut
XlsPerl.pm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
package XlsPerl; use warnings; use strict; use Carp qw(croak);
#use Readonly; use Win32::OLE; use Win32::OLE::Const 'Microsoft Excel'; use Win32::OLE::Variant; Win32::OLE->Option( Warn => 3);
use vars qw( @ObjInterfaceMethods );
# which object interface methods shell be available as standard #Readonly::Array @ObjInterfaceMethods = qw( excelFile excel workBook worksheet worksheetNumber currentRow lastRow changeCount );
# install object interface methods at startup foreach my $method ( @ObjInterfaceMethods ) { no strict 'refs'; *{ $method } = sub { my( $self, @values ) = @_; $self->{ $method } = $values[0] if scalar @values; return $self->{ $method }; }; } # foreach
# ============================================================ sub new { my( $class, %params ) = @_;
my $self = bless {}, $class; foreach my $param (keys %params) { $self->$param( $params{$param} ); } # foreach
return $self; } # new # ------------------------------------------------------------ sub DESTROY { # my $self = shift; # print "DESTROY: ", ref $self->excel, "\n"; } # DESTROY # ------------------------------------------------------------ sub increaseCurrentRow { my $self = shift; $self->currentRow( 1 + $self->currentRow ); } # increaseCurrentRow # ------------------------------------------------------------ sub increaseChangeCount { my $self = shift; $self->changeCount( 1 + $self->changeCount ); } # increaseChangeCount # ------------------------------------------------------------ sub open { my( $self ) = @_;
my $filename = $self->excelFile; defined $filename or croak "Error: no filename given"; -f $filename or croak( "Error: filename '$filename' doesn't exist");
my $excel; # try to re-use running instance of Excel eval { $excel = Win32::OLE->GetActiveObject( 'Excel.Application' ) }; die "Error: no Excel installed\n" if $@;
unless( defined $excel ) { # if not running, start excel $excel = Win32::OLE->new( 'Excel.Application', sub { $_[0]->Quit } ) or die "Error: can't start Excel\n"; } # unless $self->excel( $excel );
$self->workBook( $excel->Workbooks->Open( $filename ) );
$self->worksheet( $self->workBook->Worksheets( $self->worksheetNumber ) );
my $range = $self->worksheet->UsedRange->{Value}; $self->lastRow( $#$range + 1 );
$self->currentRow( 0 );
return $self; } # open # ------------------------------------------------------------ sub getNextRow { my( $self ) = @_;
$self->increaseCurrentRow;
my $row = $self->currentRow; my $sheet = $self->worksheet; return if $row > $self->lastRow;
my $rowData = $sheet->Range("A$row:IV$row")->{Value}; # dirty my $itemsFound = 0;
tie( @::F, 'XlsPerl::RowArray', $self );
foreach my $value ( reverse @{ $rowData->[0] } ) { if( defined $value ) { unshift( @::F, $value ); $itemsFound++; } else { unshift( @::F, '' ) if scalar @::F; } } # foreach
return 1; } # getNextRow # ------------------------------------------------------------
# ============================================================ package XlsPerl::RowArray; # ------------------------------------------------------------ use Tie::Array; use vars qw(@ISA); @ISA = qw(Tie::Array); # ------------------------------------------------------------ sub TIEARRAY { my( $class, $excelObj ) = @_;
my $self = bless( { data => [] }, $class ); $self->{excelObj} = $excelObj; $self->{row} = $excelObj->currentRow;
return $self; } # TIEARRAY # ------------------------------------------------------------ sub FETCH { my( $self, $index) = @_; return $self->{data}->[ $index ]; } # FETCH # ------------------------------------------------------------ sub STORE { my( $self, $index, $value ) = @_;
my $excelObj = $self->{excelObj}; my $sheet = $excelObj->worksheet;
my $row = $excelObj->currentRow; my $col = $index + 1;
# print "### UPDATE: $row/$col\n"; # print "OLD: '$self->{data}->[ $index ]'\n"; # print "NEW: '$value'\n\n";
if( $self->{data}->[$index] ne $value ) { $excelObj->increaseChangeCount; $sheet->Cells($row, $col)->{Value} = $value; $self->{data}->[ $index ] = $value; } # if
} # STORE # ------------------------------------------------------------ sub FETCHSIZE { my $self = shift; return $#{ $self->{data} }; } # FETCHSIZE # ------------------------------------------------------------ sub STORESIZE { my( $self, $newLength ) = @_; print "### STORESIZE\n"; $#{ $self->{data} } = $newLength; } # STORESIZE # ------------------------------------------------------------ sub UNSHIFT { my $self = shift; # print "### UNSHIFT @_\n"; unshift( @{ $self->{data} }, @_ ); } # UNSHIFT # ------------------------------------------------------------ sub SHIFT { my $self = shift; print "### SHIFT\n"; return shift @{ $self->{data} }; } # SHIFT # ------------------------------------------------------------ sub POP { my $self = shift; print "### POP\n"; return pop @{ $self->{data} }; } # POP # ------------------------------------------------------------ sub PUSH { my $self = shift; print "### PUSH\n"; push( @{ $self->{data} }, @_ ); } # PUSH # ------------------------------------------------------------ sub CLEAR { my( $self ) = @_; print "### CLEAR\n"; # TODO: update excel $self->{data} = []; } # CLEAR # ------------------------------------------------------------ sub DESTROY { # my $self = shift; } # DESTROY # ------------------------------------------------------------ # sub EXISTS { # } # EXISTS # ------------------------------------------------------------ # sub DELETE { # } # DELETE # ------------------------------------------------------------ # ... # ------------------------------------------------------------ 1; # modules have to return a true value
View full thread excelPerl
|