Does function CSV->PRINT only accept array reference? I am pushing $cell2_value in an array and then printing the array (i.e rows), it would be nice if I can directly write $cell2_value into an opened CSV file.
Things to take care of -
Excel cell having commas in their value would print in double-quotes.
Excel cells having "keyword" in their value would print the whole-cell value in double-quotes and inner quotes will change to ""keyword"".
I can write a CSV file with a few undesired outputs of excel cells. its inserting double quotes whenever it sees special characters like / or *.
CSV FILE from the below code:-
"CLASS_A,,x,Singapore,,0xABCF00C4,"/* x2-4Rw */",-,,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"CHECK- ""CLASS_B""- WORKED",1,2,3"
"CLASS_A,,,malyaisa,," 3:0","/* ABCVF */",E,,,,,,,Yes,,,,,,,,,,,,,Yes,,,,,,Yes,Yes,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"
Desired output
CLASS_A,,x,malyaisa,,0xABCF00C4,/* x2-4Rw */,-,,,,,,,Yes,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,"CHECK- ""CLASS_B""- WORKED",1,2,3
CLASS_A,,,malyaisa,, 3:0,/* ABCVF */,E,,,,,,,Yes,,,,,,,,,,,,,Yes,,,,,,Yes,Yes,Yes,,,,,,,,,,,,,,,,,,,
Why it's inserting quotes around each line? Is there any way to remove it?
sub Excel_to_CSV
{
($student_excel_file) = #_;
if($student_excel_file ne "")
{
$student_excel_out_csv_file = $student_excel_file;
$student_excel_out_csv_file =~ s/.xlsm$/_new.csv/;
my $parser_1 = Spreadsheet::ParseXLSX->new();
my $workbook = $parser_1->parse($student_excel_file);
my $csv_1 = Text::CSV->new ({ binary => 1, auto_diag => 1, sep_char => ',' });
open my $fh, ">:encoding(utf-8)", $student_excel_out_csv_file or die "failed to create $student_excel_out_csv_file: $!";
if ( !defined $workbook )
{
die $parser_1->error(), ".\n";
}
my $worksheet=$workbook_->worksheet(0);
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
printf("Copyig Sheet: %s from the provided student \n", $worksheet->{Name});
my $concurentEmptyLineCount = 0;
for my $row_1 ( $row_min .. $row_max )
{
my #row_elements_array;
for my $col_1 ( $col_min .. $col_max )
{
my $cell_1 = $worksheet->get_cell( $row_1, 0 );
next unless $cell_1;
$concurentEmptyLineCount=0;
my $cell_2 = $worksheet->get_cell( $row_1, $col_1);
my $cell2_value =$cell_2 -> {Val};
if(defined $cell2_value)
{
push(#row_elements_array, $cell2_value);
}
else
{
my $blank="";
push(#row_elements_array, $blank);
}
}
my $next_line="\n";
push(#row_elements_array, $next_line);
my #temp_row_elements_array= #row_elements_array;
$csv_1->print($fh, \#temp_row_elements_array);
}
close $fh;
}
return $student_excel_out_csv_file;
}
Based on my understanding of your requirements, one solution is to remove the extraneous double-quotes from $cell2_value before pushing it into #row_elements_array. For example:
$cell2_value =~ s/"(")*/$1/g;
push(#row_elements_array, $cell2_value);
I am trying to read an existing Excel spreadsheet and write it into a new Excel document with all the same format options.
I am able to read the cell contents and write them into the new Excel sheet, but I cannot get the background color of the cell.
If I use the $cell->get_format->{Fill}[2] method it gives me numbers like either 64 or 65 if the cell has a background color.
How can I get the actual color of a cell and apply the same background color to the cell in new Excel sheet?
I am doing all these things as there is no method available in the Spreadsheet::ParseExcel module to set the background color for a cell after appending data to an existing Excel sheet.
Here is my code
use Spreadsheet::WriteExcel;
use Spreadsheet::ParseExcel;
my $parser = Spreadsheet::ParseExcel->new();
my $workbook_parse = $parser->Parse( 'Report.xls' );
my $worksheet_parse = $workbook_parse->Worksheet( "Health_Report" );
my ( $col_min, $col_max ) = $worksheet_parse->col_range();
my ( $row_min, $row_max ) = $worksheet_parse->row_range();
my $workbook = Spreadsheet::WriteExcel->new( "Report_new.xls" );
my $worksheet = $workbook->addworksheet( "Health_Report" );
my $bkgd_color = $workbook->addformat();
for my $col ( $col_min .. $col_max ) {
for my $row ( $row_min .. $row_max ) {
# Return the cell object at $row and $col
my $cell = $worksheet_parse->get_cell( $row, $col );
next unless $cell;
my $value = $cell->value();
my $format = $cell->get_format();
my $backgroundcolor = $format->{Fill}->[2];
print "Row, Col = ($row, $col) ";
print "Value = $value\n";
print "Format = $backgroundcolor\n";
$bkgd_color->set_bg_color( $backgroundcolor );
### Here trying to rewrite into Excel and apply the
### same background color which the cell had previously
$worksheet->write( $row, $col, $value, $bkgd_color );
}
}
Part of my output from print statements:
Format = 65
Row, Col = (25, 4) Value = -115966
Format = 65
Row, Col = (10, 5) Value = 20170417
Format = 65
Row, Col = (11, 5) Value = 0
Format = 64
Row, Col = (16, 5) Value = 0
Format = 64
Update
It appears that the documentation is wrong. The name of the workbook object method is different from that of the class method, and you need to call
$workbook->color_idx_to_rgb($color_index)
instead
The documentation for Spreadsheet::ParseExcel says this
$font->{Color}
Returns the color index for the font. The mapping to an RGB color is defined by each workbook.
The index can be converted to a RGB string using the $workbook->ColorIdxToRGB() Parser method.
(Older versions of Spreadsheet::ParseExcel provided the ColorIdxToRGB class method, which is deprecated.)
I expect that the colour indexes in the $format->{Fill} array can be translated similarly
Hello Venkatesh k,
Try the set_color() method from (Spreadsheet::WriteExcel).
From the documentation:
Default state: Excels default color, usually black
Default action: Set the default color
Valid args: Integers from 8..63 or the following strings:
'black'
'blue'
'brown'
'cyan'
'gray'
'green'
'lime'
'magenta'
'navy'
'orange'
'pink'
'purple'
'red'
'silver'
'white'
'yellow'
Update: try this, it seems to be working for my example spread sheet.
#!/usr/bin/perl
use strict;
use warnings;
use Spreadsheet::WriteExcel;
use Spreadsheet::ParseExcel;
sub create_new_worksheet {
my ($row, $col, $value, $backgroundcolor) = #_;
# Create a new Excel workbook
my $workbook = Spreadsheet::WriteExcel->new('perl.xls');
# Add a worksheet
my $worksheet = $workbook->add_worksheet();
# Add and define a format
my $format = $workbook->add_format(bg_color => $backgroundcolor);
$format->set_align('center');
# Write a formatted and unformatted string, row and column notation.
$worksheet->write($row, $col, $value, $format);
}
my $parser = Spreadsheet::ParseExcel->new();
my $workbook_parse = $parser->Parse( 'Report.xls' );
my $worksheet_parse = $workbook_parse->Worksheet("Sheet1");
my ( $col_min, $col_max ) = $worksheet_parse->col_range();
my ( $row_min, $row_max ) = $worksheet_parse->row_range();
for my $col ( $col_min .. $col_max ) {
for my $row ( $row_min .. $row_max ) {
# Return the cell object at $row and $col
my $cell = $worksheet_parse->get_cell( $row, $col );
next unless $cell;
my $value = $cell->value();
my $format = $cell->get_format();
my $backgroundcolor = $format->{Fill}->[2];
print "Row, Col = ($row, $col) ";
print "Value = $value\n";
print "Format = $backgroundcolor\n";
create_new_worksheet($row, $col, $value, $backgroundcolor);
}
}
i wanted to parse a csv file in perl and want to generate an excel sheet.
As of now i am able to parse CSV file and converted into xls.This code is working properly, which is giving some 6 rows and 3 colums according to CSV.which is correct.After parsing it i want to do some formating also.let say any row or colum which has "Pass" as a string that should be of green color and fail then that should be of Red color.How can i do that please help..
#!/run/pkg/TWW-perl-/5.8.8/bin/perl -w
use strict;
use warnings;
use Spreadsheet::WriteExcel;
use Text::CSV::Simple;
use Spreadsheet::ParseExcel::Format
my $infile = "/project/ls1socdft_nobackup/rev2.0/user/Shah- B53654/dft/dfta/perl/pattern_qa/output_0/xls_info.csv";
#usage() unless defined $infile && -f $infile;
my $parser = Text::CSV::Simple->new;
my #data = $parser->read_file($infile);
my $headers = shift #data;
my $outfile = shift || "/project/ls1socdft_nobackup/rev2.0/user/Shah-B53654/dft/dfta/perl/pattern_qa/output_0/xls_info.xls";
my $subject = shift || 'worksheet';
my $workbook = Spreadsheet::WriteExcel->new($outfile);
my $bold = $workbook->add_format();
$bold->set_bold(1) ;
my $color =$workbook->add_format();
$color->set_bg_color('green');
my $color1=$workbook->add_format();
$color1->set_bg_color('red');
import_data($workbook, $subject, $headers, \#data);
# Add a worksheet
sub import_data {
my $workbook = shift;
my $base_name = shift ;
my $colums = shift;
my $data = shift;
my $limit = shift || 50_000;
my $start_row = shift ||1;
my $worksheet = $workbook->add_worksheet($base_name);
$worksheet->add_write_handler(qr[\w], \&store_string_widths);
my $w = 1;
$worksheet->write('A' . $start_row, $colums,$bold);
my $i = $start_row;
my $qty = 0;
for my $row (#$data) {
$qty++;
if ($i > $limit) {
$i = $start_row;
$w++;
$worksheet = $workbook->add_worksheet("$base_name - $w");
$worksheet->write('A1', $colums);
}
$worksheet->write(1+$i++,0, $row);}
autofit_columns($worksheet);
warn "Convereted $qty rows.";
return $worksheet;
}
sub store_string_widths {
my $worksheet = shift;
my $col = $_[1];
my $token = $_[2];
# Ignore some tokens that we aren't interested in.
return if not defined $token; # Ignore undefs.
return if $token eq ''; # Ignore blank cells.
return if ref $token eq 'ARRAY'; # Ignore array refs.
return if $token =~ /^=/; # Ignore formula
# Ignore numbers
#return if $token =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d++))?$/;
# Ignore various internal and external hyperlinks. In a real scena+rio
# you may wish to track the length of the optional strings used wi+th
# urls.
return if $token =~ m{^[fh]tt?ps?://};
return if $token =~ m{^mailto:};
return if $token =~ m{^(?:in|ex)ternal:};
# We store the string width as data in the Worksheet object. We us+e
# a double underscore key name to avoid conflicts with future name +s.
#
my $old_width = $worksheet->{__col_widths}->[$col];
my $string_width = string_width($token);
if (not defined $old_width or $string_width > $old_width) {
# You may wish to set a minimum column width as follows.
#return undef if $string_width < 10;
$worksheet->{__col_widths}->[$col] = $string_width;
}
# Return control to write();
return undef;
}
sub string_width {
return length $_[0];
}
sub autofit_columns {
my $worksheet = shift;
my $col = 0;
for my $width (#{$worksheet->{__col_widths}}) {
$worksheet->set_column($col, $col, $width) if $width;
$col++;
}
}
There are two ways you can get the individual cell formatted the way you're expecting.
1: Instead of passing an array of data into the $worksheet->write() method, loop through each row and column and write each cell individually.
EX:
change
$worksheet->write('A1', $colums);
to
for (my $r=0;$r<#$colums;$r++) {
for (my $c=0;$c<#{$colums->[$r]}) {
$worksheet->write($r,$c,$colums->[$r]->[$c]);
}
Now, you can test each value being written for your criteria. If it matches, just include the format you want to use.
$worksheet->write($r,$c,$columns->[$r]->[$c],$color1);
}
2: The other option is to use Excel::Writer::XLSX
Spreadsheet::WriteExcel is in maintenance only mode and has
effectively been superseded by Excel::Writer::XLSX.
This module is more up to date and includes functions for conditional formatting, which can be added after writing your data.
Also, there should be no change in your excel generation code except for when you include the module and when you initialize it.
Then, you just specify the rules for the conditional formatting.
$worksheet->conditional_formatting( 'A1:J10',
{
type => 'text',
criteria => 'containing',
value => 'Pass',
format => $color,
}
);
$worksheet->conditional_formatting( 'A1:J10',
{
type => 'text',
criteria => 'containing',
value => 'Fail',
format => $color1,
}
);
With the reference to the question I had asked before is:
My Code is as below:
if ( !-e $xls_file ) #Checking whether to create a new Excel file or not
{
#if yes create a new excel file and 4 worksheets
print OUTFILE "Creatin a new sheet.\n";
$excelFileHandle= Spreadsheet::WriteExcel->new($xls_file) ;
&InitFormatting ($excelFileHandle);#For format of each cell.
($handle, $row, $col) = &AddSheet("$monthYearStr", "$SHEET_TITLE", #ReportColLabels);
($handle1, $row1, $col1) = &AddSheet("$STATUS_CODE_SHEET_NAME", "$STATUS_CODE_SHEET_TITLE", #Status_Code_labels);
($handle2, $row2, $col2) = &AddSheet("$SUCCESS_COUNT_SHEET_NAME", "$SUCCESS_SHEET_TITLE", #Success_count_labels);
($handle3, $row3, $col3) = &AddSheet("$FAILURE_COUNT_SHEET_NAME", "$FAILURE_SHEET_TITLE", #Failure_count_labels);
$new = 1;
}
else #File exists needs to parsed and append the data.
{
print OUTFILE "Opening the existing sheet.\n";
my $parser = Spreadsheet::ParseExcel->new();
my $workbook = $parser->parse($xls_file);
if ( !defined $workbook )
{
die $parser->error(), ".\n";
}
my $worksheet = $workbook->worksheet($monthYearStr);
( $row_min, $row_max ) = $worksheet->row_range();
( $col_min, $col_max ) = $worksheet->col_range();
my $worksheet1 = $workbook->worksheet($monthYearStr);
( $row_min1, $row_max1 ) = $worksheet1->row_range();
( $col_min1, $col_max1 ) = $worksheet1->col_range();
$new = 0;
}
if ( $new = 1 )
{
$handle->write($row, $col++, "$present_date", $num_field_format);
------Contiuned for remainin row and col for $monthYearStr $STATUS_CODE_SHEET_NAME $SUCCESS_COUNT_SHEET_NAME $FAILURE_COUNT_SHEET_NAME-------
}
elsif ( $new == 0)
{
###Appending the data####
$parser = Spreadsheet::ParseExcel::SaveParser->new();
$template = $parser->Parse($xls_file);
if ( ! defined $template )
{
die $parser->error(), ".\n";
}
my $worksheet = $template->worksheet($monthYearStr);
my $row = $row_max + 1;
my $cell = $worksheet->get_cell( $row_max, $row_max );
my $format_number = $cell->{FormatNo};
$worksheet->AddCell($row, $col++, "$present_date", $format_number);
---------Continued for remaining row and col only for $monthYearStr $STATUS_CODE_SHEET_NAME -----------------------------
}
Now, how do I over-write the worksheet sheet success_count and failure_count each time when the excel file exists.
Please suggest me how to do this.
Its difficult to tell what to do without the AddSheet subroutine, but you should be able to overwrite the cells in a worksheet using something like this, per the POD:
foreach $worksheet ($workbook->sheets()) {
if( $worksheet->get_name() eq $SUCCESS_COUNT_SHEET_NAME ) {
$worksheet->write('A1', $success_count);
}
elsif( $worksheet->get_name() eq $FAILURE_COUNT_SHEET_NAME ) {
$worksheet->write('A1', $failure_count);
}
}