Cakephp- Date Conversion while reading from excel sheet - excel

Using Cakephp, I am reading from an Excel sheet (I'm using Libre Office) and the date is not converted properly.
I'm using PHP spreadsheet excel reader to import the excel sheet into the database.
I'm not using any functions to convert the date given in the excel sheet.
In the excel sheet the date which I have given like this 04/10/2013 is converted to this format (AprApr/WedWed/2013201320132013). I want the exact date which I have given in the excel sheet.
I'm adding my code also here:
$excel = new Spreadsheet_Excel_Reader(WWW_ROOT . 'files/excel/' . $this->request->data['Request']['file_name'], true);
$excel->setUTFEncoder('iconv');
$excel->setOutputEncoding('UTF-8');
$excel->read(WWW_ROOT . 'files/excel/' . $this->request->data['Request']['file_name']);
$x = 2;
$sep = ",";
ob_start();
while ($x <= $excel->sheets[0]['numRows']) {
$y = 1;
$row = "";
while ($y <= $excel->sheets[0]['numCols']) {
echo $excel->sheets[0]['cells'][$x][4];
$cell = isset($excel->sheets[0]['cells'][$x][$y]) ? $excel->sheets[0]['cells'][$x][$y] : '';
$row.=($row == "") ? "\"" . $cell . "\"" : "" . $sep . "\"" . $cell . "\"";
$y++;
}
echo $row . "\n";
$x++;
}
$fp = fopen(WWW_ROOT . "files/excel/data.csv", 'w');
fwrite($fp, ob_get_contents());
fclose($fp);
ob_end_clean();
$filehandle = fopen(WWW_ROOT . "files/excel/data.csv", "r");
fgetcsv($filehandle, 1000, ",");
while (($data = fgetcsv($filehandle, ",")) !== FALSE) {
pr($data);
}
Please help!!! Thanks in advance

Related

phpmailer write debug inside log file

I tried to create a new log file if there is a phpmailer error. But the file is not created. I check my directory (777).
Do you have an idea ?
Thank you
if (DEBUG_EMAIL == 'true'){
$this->phpMail->SMTPDebug = $this->debug_level; //2
$this->phpMail->Debugoutput = function($str, $level) {
$filename = CLICSHOPPING::BASE_DIR . 'Work/Log/phpmail_error-' . date('Ymd') . '.log';
$data = date('Y-m-d H:i:s') . "\t" . "\t$level\t$str\n";
$flags = FILE_APPEND | LOCK_EX;
file_put_contents($filename, $data, $flags);
};
// $this->phpMail->SMTPDebug = SMTP::DEBUG_SERVER;
}
Double check all your values, don't assume they are what you think they are. For example what is in CLICSHOPPING::BASE_DIR? Also, it's usual for directory env vars to not have a trailing slash, so you may be missing one when you append Work/... to it. Try this:
$filename = CLICSHOPPING::BASE_DIR . '/Work/Log/phpmail_error-' . date('Ymd') . '.log';
$data = date('Y-m-d H:i:s') . "\t" . "\t$level\t$str\n";

How to automatically change the format or encode the excel cell value while writing it to CSV file

My script is breaking when excel cell has double quotes in their value and quotes. I had to explicitly write a function to handle commas in OUTFILE. Is there any way I can provide cell value and automatically it can be encoded to CSV format.
example-
cell->value - Student GOT 8 MARKS in math, 7 in Spanish
Desired Correct CSV format-> "Student GOT 8 MARKS in math, 7 in Spanish".
cell->value - Student GOT 8 MARKS in "math", 7 in "Spanish"
Desired Correct CSV format-> "Student GOT 8 MARKS in ""math"", 7 in ""Spanish""".
I wrote my function to find COMMAS in cell value and if it exits then put the string in double-quotes. I wanted to avoid it in case there are any built functions of CSV writer.
#!/home/utils/perl-5.08
use Text::CSV_XS;
use Text::CSV;
use Excel::Writer::XLSX;
use Spreadsheet::ParseXLSX;
use CGI qw(:standard);
use DBI;
use DBD::CSV;
my $student_excel_file = "";
my $csv = "";
$student_excel_file='ABC.xlsm';
$csv = $student_excel_file;
$csv =~ s/.xlsx$/_22june_intermediate_xlsxtocsv.csv/;
$csv =~ s/.xlsm$/_22june_intermediate_xlsmtocsv.csv/;
my $parser_1 = Spreadsheet::ParseXLSX->new();
my $workbook_1 = $parser_1->parse($student_excel_file);
printf "$csv\n";
print "writing out the new csv file $csv given prvs xlsm file\n";
my $csv_1 = Text::CSV_XS->new ({ binary => 1, auto_diag => 1, eol => "\r\n", sep_char => ',' });
open my $fh, ">:encoding(utf-8)", $csv or die "failed to create $csv: $!";
#open OUTFILE, "> $student_excel_out_csv_file" or die "ERROR: can't the student;'s CSV file:- $student_excel_out_csv_file.\n";
if ( !defined $workbook_1 )
{
die $parser_1->error(), ".\n";
}
my $worksheet_1=$workbook_1->worksheet(0);
my ( $row_min, $row_max ) = $worksheet_1->row_range();
my ( $col_min, $col_max ) = $worksheet_1->col_range();
printf("Copyig Sheet: %s from the provided PRVS \n", $worksheet_1->{Name});
my $reached_end_of_sheet = 0;
my $concurentEmptyLineCount = 0;
$col_max=65;
#$row_max=2;
my(#heading) = ("CodeA", "CodeB", "Name", "Count", "Pos", "Orientation");
$csv_1->print($fh, \#heading);
my(#datarow) = ("A", "B", "Abelone", 3, "(6,9)", "NW");
$csv_1->print($fh, \#datarow);
my(#datarow_1) = ("A", "B", "Abelone", 3, "WORKS - ""what"" - lets", "_2NW");
$csv_1->print($fh, \#datarow_1);
for my $worksheet ( $workbook->worksheets() ) {
my ( $row_min, $row_max ) = $worksheet->row_range();
my ( $col_min, $col_max ) = $worksheet->col_range();
printf("Sheet: %s\n", $worksheet->{Name});
my $sheet_write = $excel_2->add_worksheet($worksheet->{Name});
# my $format = $sheet_write->add_format();
for my $row_1 ( 1 .. $row_max )
{
if($reached_end_of_sheet)
{
last;
}
for my $col_1 ( $col_min .. $col_max )
{
my $cell_1 = $worksheet_1->get_cell( $row_1, 0 );
next unless $cell_1;
$concurentEmptyLineCount=0;
my $cell_2 = $worksheet_1->get_cell( $row_1, $col_1);
my $cell2_value =$cell_2 -> {Val};
print $cell_2 -> {Val};
$csv_1->print ($fh, \$cell2_value );
# if(defined $cell2_value)
# {
# if($cell2_value=~ m/,/)
# {
# $cell2_value=qq("$cell2_value");
# }
# printf OUTFILE "%s,", $cell2_value;
# }
# else
# {
# printf OUTFILE ",";}
# }
my $cell_3 = $worksheet_1->get_cell( $row_1, 0 );
$concurentEmptyLineCount++;
if($concurentEmptyLineCount > 20)
{
$reached_end_of_sheet = 1;
}
next unless $cell_3;
#printf OUTFILE "\n";
$csv_1->print ($fh, "\n" );
}
#close OUTFILE;
close $fh;
exit;
You can use combine() to quote the fields. For example:
use feature qw(say);
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new();
my #fields = (
q[Student GOT 8 MARKS in math, 7 in Spanish],
q[Student GOT 8 MARKS in "math", 7 in "Spanish"],
);
for my $field (#fields) {
my $success = $csv->combine($field);
if (!$success) {
die "Failed to quote field: " . $field;
}
say "Result: ", $csv->string();
}
Output:
Result: "Student GOT 8 MARKS in math, 7 in Spanish"
Result: "Student GOT 8 MARKS in ""math"", 7 in ""Spanish"""

What is the fastest way to increment a string in perl?

I would like to append a string in perl within a loop in a fast way, without having to copy the string for each iteration. I'm looking for something like StringBuilder from Java or C#.
I currently know the following alternatives in mind, in order to do 'a += b'.
a .= b # concat
a = join('', a, b); # join
push #a, b # array push
I am not interested in copying all string to the other. I need to copy one character per time, or append small strings foreach iteration. I am trying to solve the following problem: compress the input string 'aaabbccc' to '3a2b3c'. So the idea is to iterate over the input string, check how many repeated characters we have, and then append to the output in the compressed way. What is the most efficient to perform this in perl ?
Here is a link to the problem I was trying to solve. I's slightly different though.
For comparsion, I tried to test different versions for solving your actual problem of compressing the string. Here is my test script test.pl:
use strict;
use warnings;
use Benchmark qw(cmpthese);
use Inline C => './compress_c.c';
my $str_len = 10000;
my #chars = qw(a b c d);
my $str;
$str .= [#chars]->[rand 4] for 1 .. $str_len;
cmpthese(
-1,
{
compress_array => sub { compress_array( $str ) },
compress_regex => sub { compress_regex( $str ) },
compress_str => sub { compress_str( $str ) },
compress_c => sub { compress_c( $str ) },
}
);
# Suggested by #melpomene in the comments
sub compress_regex {
return $_[0] =~ s/([a-z])\1+/($+[0] - $-[0]) . $1/egr;
}
sub compress_array {
my $result = '';
my #chrs = split //, $_[0];
my $prev = $chrs[0];
my $count = 1;
my #result;
for my $i ( 1..$#chrs ) {
my $char = $chrs[$i];
if ( $prev eq $char ) {
$count++;
next if $i < $#chrs;
}
if ( $count > 1) {
push #result, $count, $prev;
}
else {
push #result, $prev;
}
if ( ( $i == $#chrs ) and ( $prev ne $char ) ) {
push #result, $char;
last;
}
$count = 1;
$prev = $char;
}
return join '', #result;
}
sub compress_str {
my $result = '';
my $prev = substr $_[0], 0, 1;
my $count = 1;
my $lastind = (length $_[0]) - 1;
for my $i (1 .. $lastind) {
my $char = substr $_[0], $i, 1;
if ( $prev eq $char ) {
$count++;
next if $i < $lastind;
}
if ( $count > 1) {
$result .= $count;
}
$result .= $prev;
if ( ( $i == $lastind ) and ( $prev ne $char ) ) {
$result .= $char;
last;
}
$count = 1;
$prev = $char;
}
return $result;
}
where compress_c.c is:
SV *compress_c(SV* str_sv) {
STRLEN len;
char* str = SvPVbyte(str_sv, len);
SV* result = newSV(len);
char *buf = SvPVX(result);
char prev = str[0];
int count = 1;
int j = 0;
int i;
for (i = 1; i < len; i++ )
{
char cur = str[i];
if ( prev == cur ) {
count++;
if ( i < (len - 1) )
continue;
}
if ( count > 1) {
buf[j++] = count + '0'; // assume count is less than 10
}
buf[j++] = prev;
if ( (i == (len - 1)) && (prev != cur) ) buf[j++] = cur;
count = 1;
prev = cur;
}
buf[j] = '\0';
SvPOK_on(result);
SvCUR_set(result, j);
return result;
}
The result of running perl test.pl:
Rate compress_array compress_str compress_regex compress_c
compress_array 311/s -- -42% -45% -99%
compress_str 533/s 71% -- -6% -98%
compress_regex 570/s 83% 7% -- -98%
compress_c 30632/s 9746% 5644% 5273% --
Which shows that regex version is slightly faster than the string version. However, the C version is the fastest, and it is about 50 times as fast as the regex version.
Note: I tested this on my Ubuntu 16.10 laptop (Intel Core i7-7500U CPU # 2.70GHz)
I've performed the following benchmark in several ways to perform that:
#!/usr/bin/perl
use strict;
use warnings;
use Benchmark qw(cmpthese);
my $dna;
$dna .= [qw(G A T C)]->[rand 4] for 1 .. 10000;
sub frequency_concat {
my $result = '';
for my $idx (0 .. length($dna) - 1) {
$result .= substr($dna, $idx, 1);
}
return $result;
}
sub frequency_join {
my $result = '';
for my $idx (0 .. length($dna) - 1) {
$result = join '', $result, substr($dna,$idx,1);
}
return $result;
}
sub frequency_list_push {
my #result = ();
for my $idx (0 .. length($dna) - 1) {
push #result, substr($dna,$idx,1);
}
return join '', #result;
}
sub frequency_list_prealloc {
my #result = (' ' x length($dna));
for my $idx (0 .. length($dna) - 1) {
$result[$idx] = substr($dna,$idx,1);
}
return join '', #result;
}
cmpthese(-1, # Run each for at least 1 second(s) {
concat => \&frequency_concat,
join => \&frequency_join,
list_push => \&frequency_list_push,
list_list_prealloc => \&frequency_list_prealloc
}
);
The results below have shown that the concat (a . b) is the fastest operation. I don't understand why, since this will need to make several copies of the string.
Rate join list_push list_list_prealloc concat
join 213/s -- -38% -41% -74%
list_push 342/s 60% -- -5% -58%
list_list_prealloc 359/s 68% 5% -- -56%
concat 822/s 285% 140% 129% --

Calculating the Mean from aPerl Script

I m still in here. ;)
I've got this code from a very expert guy, and I'm shy to ask him this basic questions...anyway this is my question now; this Perl Script prints the median of a column of numbers delimited space, and, I added some stuff to get the size of it, now I'm trying to get the sum of the same column. I did and got not results, did I not take the right column? ./stats.pl 1 columns.txt
#!/usr/bin/perl
use strict;
use warnings;
my $index = shift;
my $filename = shift;
my $columns = [];
open (my $fh, "<", $filename) or die "Unable to open $filename for reading\n";
for my $row (<$fh>) {
my #vals = split/\s+/, $row;
push #{$columns->[$_]}, $vals[$_] for 0 .. $#vals;
}
close $fh;
my #column = sort {$a <=> $b} #{$columns->[$index]};
my $offset = int($#column / 2);
my $length = 2 - #column % 2;
my #medians = splice(#column, $offset, $length);
my $median;
$median += $_ for #medians;
$median /= #medians;
print "MEDIAN = $median\n";
################################################
my #elements = #{$columns->[$index]};
my $size = #elements;
print "SIZE = $size\n";
exit 0;
#################################################
my $sum = #{$columns->[$index]};
for (my $size=0; $size < $sum; $size++) {
my $mean = $sum/$size;
};
print "$mean\n";
thanks in advance.
OK some pointers to get you going :
You can put all the numbers into an array :
my #result = split(m/\d+/, $line);
#average
use List::Util qw(sum);
my $sum = sum(#result);
You can then access individual columns with $result[$index] where index is the number of column you want to access.
Also note that :
$total = $line + $total;
$count = $count + 1;
Can be rewritten as :
$total += $line;
$count += 1;
Finally make sure that you are reading the file :
put a "debugging" print into the while loop :
print $line, "\n";
This should get you going :)

How to turn an array of words into an array containing the characters of the words in order?

I have an array of unknown number of words, with an unknown max length.
I need to convert it to another array, basically turning it into a column word array.
so with this original array:
#original_array = ("first", "base", "Thelongest12", "justAWORD4");
The resluting array would be:
#result_array = ("fbTj","iahu","rses","selt","t oA"," nW"," gO"," eR"," sD"," t4"," 1 "," 2 ");
Actually I will have this:
fbTj
iahu
rses
selt
t oA
nW
gO
eR
sD
t4
1
2
I need to do it in order to make a table, and these words are the table's headers.
I hope I have made myself clear, and appreciate the help you are willing to give.
I tried it with the split function, but I keep messing it up...
EDIT:
Hi all, thanks for all the tips and suggestions! I learned quite much from all of you hence the upvote. However I found tchrist's answer more convenient, maybe because I come from a c,c# background... :)
use strict;
use warnings;
use 5.010;
use Algorithm::Loops 'MapCarU';
my #original_array = ("first", "base", "Thelongest12", "justAWORD4");
my #result_array = MapCarU { join '', map $_//' ', #_ } map [split //], #original_array;
I have an old program that does this. Maybe you can adapt it:
$ cat /tmp/a
first
base
Thelongest12
justAWORD4
$ rot90 /tmp/a
fbTj
iahu
rses
selt
t oA
nW
gO
eR
sD
t4
1
2
Here’s the source:
$ cat ~/scripts/rot90
#!/usr/bin/perl
# rot90 - tchrist#perl.com
$/ = '';
# uncomment for easier to read, but not reversible:
### #ARGV = map { "fmt -20 $_ |" } #ARGV;
while ( <> ) {
chomp;
#lines = split /\n/;
$MAXCOLS = -1;
for (#lines) { $MAXCOLS = length if $MAXCOLS < length; }
#vlines = ( " " x #lines ) x $MAXCOLS;
for ( $row = 0; $row < #lines; $row++ ) {
for ( $col = 0; $col < $MAXCOLS; $col++ ) {
$char = ( length($lines[$row]) > $col )
? substr($lines[$row], $col, 1)
: ' ';
substr($vlines[$col], $row, 1) = $char;
}
}
for (#vlines) {
# uncomment for easier to read, but again not reversible
### s/(.)/$1 /g;
print $_, "\n";
}
print "\n";
}
use strict;
use warnings;
use List::Util qw(max);
my #original_array = ("first", "base", "Thelongest12", "justAWORD4");
my #new_array = transpose(#original_array);
sub transpose {
my #a = map { [ split // ] } #_;
my $max = max(map $#$_, #a);
my #out;
for my $n (0 .. $max) {
$out[$n] .= defined $a[$_][$n] ? $a[$_][$n] : ' ' for 0 .. $#a;
}
return #out;
}
It can be done easily by this simple one-liner:
perl -le'#l=map{chomp;$m=length if$m<length;$_}<>;for$i(0..$m-1){print map substr($_,$i,1)||" ",#l}'

Resources