martinslmn has asked for the wisdom of the Perl Monks concerning the following question:

Hi All, I am trying to sort Excel Sheet by colors. I am using OLE. I have generated the following Macro. But I am having hard time converting it into Perl.
ActiveWorkbook.Worksheets("ami_emr_appointments").Sort.SortFields.Clea +r ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range( _ "A2:A4680"), xlSortOnCellColor, xlAscending, , xlSortNormal).S +ortOnValue.Color _ = RGB(255, 0, 0) ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range( _ "A2:A4680"), xlSortOnCellColor, xlAscending, , xlSortNormal).S +ortOnValue.Color _ = RGB(255, 255, 0) ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range( _ "B2:B4680"), xlSortOnCellColor, xlAscending, , xlSortNormal).S +ortOnValue.Color _ = RGB(255, 255, 0) ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range( _ "C2:C4680"), xlSortOnCellColor, xlAscending, , xlSortNormal).S +ortOnValue.Color _ = RGB(255, 255, 0) ActiveWorkbook.Worksheets("Sheet1").Sort.SortFields.Add(Range( _ "B2:B4680"), xlSortOnCellColor, xlAscending, , xlSortNormal).S +ortOnValue.Color _ = RGB(255, 255, 0) With ActiveWorkbook.Worksheets("Sheet1").Sort .SetRange Range("A1:W4680") .Header = xlYes .MatchCase = False .Orientation = xlTopToBottom .SortMethod = xlPinYin .Apply End With
Can you please help by pointing me in the right direction? Previously I was using manual sorting on Excel 2003 using the following code. It takes a long time to complete. As latest versions of Excel supports Sort by Colour, I would like to move to it. This will give you an idea on what I am looking for.
sub sortByColor() { my $filename = $_[0]; my $no_of_columns = $_[1]; say "Activate $filename"; say "No Of COlumns = $no_of_columns"; $excel->{DisplayAlerts}=0; $excel->Windows($filename)->Activate; $workbook = $excel->Activewindow; $sheet1=$workbook-> Activesheet; my $rows= $sheet1->UsedRange->Rows->{'Count'}; my $cols= $sheet1->UsedRange->Columns->{'Count'}; my $red_count = 0; my $sorted_count = 0; foreach my $row ( 2 .. $rows ) { #next unless defined $sheet1->Cells($row,1)->{'Value'}; my $Range = $sheet1->Range("A$row:A$row"); if ($Range->Interior()->ColorIndex() == 3) { $sheet1->rows($row . ":" . $row)->cut(); my $rngIns=$sheet1->Range(($red_count+2) . ":" . ($red_cou +nt+2)); $rngIns->EntireRow->Insert; $sheet1->rows(($red_count+2) . ":" . ($red_count+2))->Sele +ct(); $sheet1->paste(); $red_count = $red_count + 1; $sorted_count = $sorted_count + 1; } } my $column =""; foreach my $col ( 1 .. $no_of_columns) { $column = colIdToString($col); foreach my $row ( ($sorted_count+2) .. $rows ) { #next unless defined $sheet1->Cells($row,$col)->{'Value'}; my $Range = $sheet1->Range("$column$row:$column$row"); if ($Range->Interior()->ColorIndex() == 6 ) { $sheet1->rows($row . ":" . $row)->cut(); my $rngIns=$sheet1->Range(($sorted_count + 2) . ":" . +($sorted_count+2)); $rngIns->EntireRow->Insert; $sheet1->rows(($sorted_count + 2) . ":" . ($sorted_cou +nt+2))->Select(); $sheet1->paste(); $sorted_count = $sorted_count + 1; } } } }
Thanks

Replies are listed 'Best First'.
Re: Perl OLE Excel Sort By Color
by Corion (Patriarch) on Jun 02, 2015 at 12:18 UTC

    If you already have working Visual Basic code, why don't you convert that code to Perl? It's pretty straightforward.

    1. Add use Win32::OLE::Constant 'Microsoft Excel';
    2. Convert all . to ->
    3. Add $ before all variable names
    4. Convert all named arguments / keywords to hashes:
      MyFunction( Foo= bar )

      becomes

      MyFunction( { Foo => $bar } );
    5. Replace False by undef and True by 1
    6. For bonus points, eliminate all ActiveWorksheet calls and replace them by assignments to variables
      Hi, The current converted code I have is
      my $sheet1 = $workbook->Worksheets(1)->{Name}; $sheet1=$workbook->Worksheets($sheet1); $sheet1->Activate; my $rows=$sheet1->UsedRange->Rows->{'Count'}; $sheet1->Sort->SortFields->Add($sheet1->Range("A2:A" . $rows),xlSortOn +CellColor, xlAscending, xlSortNormal)->SortOnValue->{Color} = RGB(255 +, 0, 0);
      I am getting the error on RGB, and I don't know what is the replacement for it in Perl. Kindly help.

        Looking at Corion's google search I found this link where someone claims that

        RGB(a,b,c)=a*1+b*256+c*256^2

        Easy enough to translate into Perl:

        sub RGB { my ( $red, $green, $blue ) = @_; return $red + ($green<<8) + ($blue<<16); }
Re: Perl OLE Excel Sort By Color
by AnomalousMonk (Archbishop) on Jun 02, 2015 at 13:02 UTC
    sub sortByColor()
    {
        my $filename = $_[0];
        my $no_of_columns = $_[1];
        ...
    }

    The quoted code from the OP defines a subroutine that is prototyped to take no parameters, and its first two statements operate on the first two passed parameters! One way or the other, this isn't going to work. Standard prototype warning to the novice Perler: Please don't use prototypes in Perl unless you know what they do. Please see Prototypes in perlsub and especially Far More than Everything You've Ever Wanted to Know about Prototypes in Perl -- by Tom Christiansen.


    Give a man a fish:  <%-(-(-(-<

      Hi All, Thank you very much for your input. Here is the working code.
      my $Class = "Excel.Application"; my $excel = Win32::OLE->GetActiveObject($Class); if ( ! $excel ) { $excel = new Win32::OLE( $Class ) || die "Could not create an OLE '$Class' object"; } $excel -> {Visible} = 1; $excel->{'DisplayAlerts'} = 0; sortByColor("D:/sort.xls",12); sub sortByColor() { my $filename = $_[0]; my $no_of_columns = $_[1]; $excel->{DisplayAlerts}=0; my $workbook = $excel->Workbooks->Open($filename); my $sheet1=$workbook-> Activesheet; my $rows= $sheet1->UsedRange->Rows->{'Count'}; my $cols= $sheet1->UsedRange->Columns->{'Count'}; my $lastColumn = colIdToString($cols); $sheet1->Range("A1:" . $lastColumn . $rows)->Select(); $sheet1->Sort->SortFields->Clear(); $sheet1->Sort->SortFields->Add($sheet1->Range("A2:A" . $rows),xlSo +rtOnCellColor, xlAscending, xlSortNormal)->SortOnValue->{Color} = RGB +(255, 0, 0); for (my $i = 1; $i <= $no_of_columns; $i++) { my $columnString = colIdToString($i); say "Adding COlumn $columnString to Sort"; $sheet1->Sort->SortFields->Add($sheet1->Range($columnString . +"2:" . $columnString . $rows),xlSortOnCellColor, xlAscending, xlSortN +ormal)->SortOnValue->{Color} = RGB(255, 255, 0); } $sheet1->Sort->SetRange($sheet1->Range("A1:" . $lastColumn . $rows +)); say Win32::OLE->LastError(); $sheet1->Sort->{Header} = xlYes; $sheet1->Sort->{MatchCase} = "False"; $sheet1->Sort->{Orientation} = xlTopToBottom; $sheet1->Sort->{SortMethod} = xlPinYin; $sheet1->Sort->Apply; } sub RGB { my ( $red, $green, $blue ) = @_; return $red + ($green<<8) + ($blue<<16); } sub colIdToString{ my $col = $_[0]; my $column = ""; switch ($col) { case 1 {$column="A"} case 2 {$column="B"} case 3 {$column="C"} case 4 {$column="D"} case 5 {$column="E"} case 6 {$column="F"} case 7 {$column="G"} case 8 {$column="H"} case 9 {$column="I"} case 10 {$column="J"} case 11 {$column="K"} case 12 {$column="L"} case 13 {$column="M"} case 14 {$column="N"} case 15 {$column="O"} case 16 {$column="P"} case 17 {$column="Q"} case 18 {$column="R"} case 19 {$column="S"} case 20 {$column="T"} case 21 {$column="U"} case 22 {$column="V"} case 23 {$column="W"} case 24 {$column="X"} case 25 {$column="Y"} case 26 {$column="Z"} } return $column; }

        May I offer a slightly more general alternative to your sub colIdToString:

        sub colIdToString { my $col = shift; my $column = ""; while( $col ) { my $remainder = ($col-1) % 26 + 1; $column = chr( $remainder + 64 ).$column; $col -= $remainder; $col /= 26; } return $column; }
        sortByColor("D:/sort.xls",12);

        sub sortByColor()
        {
            my $filename = $_[0];
            my $no_of_columns = $_[1];
            ...
        }

        You are still prototyping the  sortByColor subroutine to take no parameters. You are calling the subroutine and passing it two parameters in such a way as to defeat prototype checking. I suppose one might ask why one would use prototypes in such a way, but if you're happy with the code, so am I!

        More importantly, you also are apparently running your code without warnings enabled. I think this is a bad idea for one new to Perl coding (and also for the experienced): I strongly recommend that you enable them.


        Give a man a fish:  <%-(-(-(-<