Converting csv to xls using Data::Table::Excel? - perl

How do you use Data::Table::Excel for converting .csv to .xls file format.
I want to do the conversion with the tables2xls subroutine:
my $t = Data::Table::fromFile("testresults-2013-07-01.csv");
my #arr = $t->csv;
Data::Table::Excel::tables2xls("results.xls", $t ,\#arr);
I tried the code above but I was not able get what I expected.

Last line must be:
Data::Table::Excel::tables2xls("results.xls", [$t] ,["Sheet name for your Table"]);
And here is colors example like you want:
Data::Table::Excel::tables2xls("results.xls", [$t] ,["Sheet name for your Table"], [["white","silver","gray"]]);

Related

Convert Date to correct format

I have CSV file with incorrect date format 19-08-22:01:00 (yy-MM-dd:HH:mm)
When I open it in excel it is not showing in date format. So I would like to convert this value using powershell.
I tried to change it using below command. But didnt work
$d = '19-08-22:01:00'
get-date $d
Could someone please help me to convert the date in correct format in which excel recognize it as date.
I would use DateTime.ParseExact():
$OldDate = '19-08-22:01:00'
# We need a provider so we pick the invariant one.
$Provider = [CultureInfo]::InvariantCulture
$OldDateFormat = 'yy-MM-dd:HH:mm'
# This format works well with Excel, assuming you use . and not , as a radix
$NewDateFormat = 'yyyy-MM-dd HH:mm:ss.fff'
$NewDate = [DateTime]::ParseExact($OldDate, $OldDateFormat, $Provider)
$NewDate.ToString($NewDateFormat)
If your only goal is fixing the format, you just need to replace that first colon with a space:
$d -replace '(?<=-\d{1,2}):', ' '

Perl : converting csv file to xml

I'm trying to parse a csv file and convert it to XML. The .csv file consists of a list of entries, separated by commas. So, two sample entries look like this:
AP,AB,A123,B123,,,
MA,NA,M123,TEXT,TEXT,TEXT_VALUE
Some field are blank in file and file has no header rows.
Any suggestions how to go with this. Haven't figured out how to go with this.
Thanks.
print "<myXML>\n";
while (<>) {
print "<aRow>$_</aRow>\n";
}
print "</myXML>\n";
Or, using XML::LibXML, something like this:
#!/usr/bin/perl
use strict;
use warnings;
use XML::LibXML;
my $doc = XML::LibXML::Document->createDocument;
my $root = $doc->createElement('myXML');
$doc->setDocumentElement($root);
$root->appendChild($doc->createTextNode("\n"));
while (<>) {
chomp;
my $row = $doc->createElement('aRow');
$root->appendChild($row);
$row->appendChild($doc->createTextNode($_));
$root->appendChild($doc->createTextNode("\n"));
}
print $doc->toString;
Of course, if you told us what the output should look like, we could probably come up with something a little more sophisticated!

comparing CSV files in Perl

I have two large CSV files which I need to compare on a daily base:
file1:
"Record number";"€ price"
"000001";"€ 19,95"
"000002";"€ 20,50"
file2:
record number;price;date
000001;18,95;01-01-2014
000002;21,50;02-02-2014
file1 contains line feeds after every record
file2 contains line feed and carriage return after every record.
I'm looking for a way in Perl to compare file1 with file2 based on record number, and print differences on the price column in a seperate file. (record number, price and date).
Hope anyone can give some advice on how to approach this?
Thanks in advance!
I am sure there are quicker and more efficient ways to do this, but below should do the job you describe. I have compared the two files by creating a hash therefore I have assumed that the record numbers are unique. I have commented the code to explain each step
#!/usr/bin/perl
use strict;
use warnings;
#declare hashes and arrays
my %file1_price;
my %file2_price;
my %file2_date;
my #file1_records;
#open the two files with the data
open (FILE1,'</path/to/file1.txt');
open (FILE2,'</path/to/file2.txt');
#open a third file to write the data out to
open (FILE3,'>/write/to/new_file.txt');
#get rid of the headers in both files
my #file1 = (<FILE1>);
my $file1_header = shift(#file1);
my #file2 = (<FILE2>);
my $file2_header = shift(#file2);
#start a loop in file 1 and change the data format to compare to file 2
foreach my $file1_data (#file1){
chomp $file1_data;
my ($file1_record, $file1_price) = split(/;/,$file1_data);
# get rid of the quotes in both variables
$file1_record =~s/"//g;
$file1_price =~s/"//g;
#get rid of the € and substitute the comma for a decimal point
$file1_price =~s/€//g;
$file1_price =~s/,/./g;
#create a hash for the price for later comparison
$file1_price{$file1_record} = $file1_price;
push #file1_records, $file1_record;
}
#start a loop in file 2 similar to the above loop ready to compare to file 1
foreach my $file2_data (#file2){
chomp $file2_data;
my ($file2_record, $file2_price, $file2_date) = split(/;/,$file2_data);
#substitute the comma for a decimal point
$file2_price =~s/,/./g;
#create hashes of the data for final comparison below
$file2_price{$file2_record} = $file2_price;
$file2_date{$file2_record} = $file2_date;
}
#final loop to compare both files' information
foreach my $record (#file1_records){
#find the difference between the two prices
my $difference = $file1_price{$record} - $file2_price{$record};
#print out to file
print FILE3 "$record, $file1_price{$record}, $file2_price{$record}, $difference,$file2_date{$record}\n";
}

new to Perl - CSV - find a string and print all numbers in that column

I've got a bunch of data in a CSV file, first row is all strings (all text and underscores), all subsequent rows are filled with numbers relating to said strings.
I'm trying to parse through the first line and find particular strings, remember which column that string was in, and then go through the rest of the file and get the data in the same column. I need to do this to three strings.
I've been using Text::CSV but I can't figure out how to get it to increment a counter until it finds the string in the first line and then go to the next line, get the data from that same column, etc. etc. Here's what I've tried so far:
while (<CSV>) {
if ($csv->parse($data)) {
my #field = $csv->fields;
my $count = 0;
for $column (#field) {
print ++$count, " => ", $column, "\n";
}
} else {
my $err = $csv->error_input;
print "Failed to parse line: $err";
}
}
Since $data is in line 1, it prints "1 $data" 25 times (# of lines in CSV file). How do I get it to remember which column it found $data in? Also, since I know all of the strings are in line 1, how do I get it to only parse through line 1, find all of the strings in #data, and then parse through the rest of the file, grabbing data from the necessary columns and putting it into a matrix or array of arrays?
Thanks for the help!
edit: I realized my questions were a bit poorly phrased. I don't know how to get the column number from CSV. How is this done?
Also, once I've got the column number, how do I tell it CSV to run through the subsequent lines and grab data from only that column?
Try something like this:
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new({binary=>1});
my $thing_to_match = "blah";
my $matched_index;
my #stored_data = ();
while(my $row= $csv->getline(*DATA)) #grabs lines below __DATA__
#(near the end of the script)
{
my #fields = #$row;
#If we haven't found the matched index, yet, search for it.
if(not defined $matched_index)
{
foreach my $i(0..$#fields)
{
$matched_index = $i if($fields[$i] eq $thing_to_match);
}
}
#NOTE: We're pushing a *reference* to an array!
#Look at perldoc perldata
push #stored_data,\#fields;
}
die "Column for '$thing_to_match' not found!" unless defined $matched_index;
foreach my $row(#stored_data)
{
print $row->[$matched_index] . "\n";
}
__DATA__
stuff,more stuff,yet more stuff
"yes, this thing, is one item",blah,blarg
1,2,3
The output is:
more stuff
blah
2
I don't have time to write up a full example, but I wrote a module that might help you do this. Tie::Array::CSV uses some magic to make your csv file act like a Perl array of arrayrefs. In this way you can use your knowledge of Perl to interact with the file.
A word of warning though! One benefit of my module is that it is read/write. Since you only want read, be careful not to assign to it!

How can I check if contents of one file exist in another in Perl?

Requirement:-
File1 has contents like -
ABCD00000001,\some\some1\ABCD00000001,Y,,5 (this indicates there are 5 file in total in unit)
File2 has contents as ABCD00000001
So what i need to do is check if ABCD00000001 from File2 exist in File1 -
if yes{
print the output to Output.txt till it finds another ',Y,,X'}
else{ No keep checking}
Anyone? Any help is greatly appreciated.
Hi Arkadiy Output should be :- any filename from file 2 -ABCD00000001 in file1 and from Y to Y .
for ex :- file 1 structure will be :-
ABCD00000001,\some\some1\ABCD00000001,Y,,5
ABCD00000001,\some\some1\ABCD00000002
ABCD00000001,\some\some1\ABCD00000003
ABCD00000001,\some\some1\ABCD00000004
ABCD00000001,\some\some1\ABCD00000005
ABCD00000001,\some\some1\ABCD00000006,Y,,2
so out put should contain all line between
ABCD00000001,\some\some1\ABCD00000001,Y,,5 and
ABCD00000001,\some\some1\ABCD00000006,Y,,2
#!/usr/bin/perl -w
use strict;
my $optFile = "C:\\Documents and Settings\\rgolwalkar\\Desktop\\perl_scripts\\SampleOPT1.opt";
my $tifFile = "C:\\Documents and Settings\\rgolwalkar\\Desktop\\perl_scripts\\tif_to_stitch.txt";
print "Reading OPT file now\n";
open (OPT, $optFile);
my #opt_in_array = <OPT>;
close(OPT);
foreach(#opt_in_array){
print();
}
print "\nReading TIF file now\n";
open (TIF, $tifFile);
my #tif_in_array = <TIF>;
close(TIF);
foreach(#tif_in_array){
print();
}
so all it does it is reads 2 files "FYI -> I am new to programming"
Try breaking up your problem into discrete steps. It seems that you need to do this (although your question is not very clear):
open file1 for reading
open file2 for reading
read file1, line by line:
for each line in file1, check if there is particular content anywhere in file2
Which part are you having difficulty with? What code have you got so far? Once you have a line in memory, you can compare it to another string using a regular expression, or perhaps a simpler form of comparison.
OK, I'll bite (partially)...
First general comments. Use strict and -w are good, but you are not checking for the results of open or explicitly stating your desired read/write mode.
The contents of your OPT file kinda sorta looks like it is CSV and the second field looks like a Windows path, true? If so, use the appropriate library from CPAN to parse CSV and verify your file names. Misery and pain can be the result otherwise...
As Ether stated earlier, you need to read the file OPT then match the field you want. If the first file is CSV, first you need to parse it without destroying your file names.
Here is a small snippet that will parse your OPT file. At this point, all it does is print the fields, but you can add logic to match to the other file easily. Just read (slurp) the entire second file into a single string and match with your chosen field from the first:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $csv = Text::CSV->new();
my #opt_fields;
while (<DATA>) {
if ($csv->parse($_)) {
push #opt_fields, [ $csv->fields() ];
} else {
my $err = $csv->error_input;
print "Failed to parse line: $err";
}
}
foreach my $ref (#opt_fields) {
# foreach my $field (#$ref) { print "$field\n"; }
print "The anon array: #$ref\n";
print "Use to match?: $ref->[0]\n";
print "File name?: $ref->[1]\n";
}
__DATA__
ABCD00000001,\some\some1\ABCD00000001,Y,,5
ABCD00000001,\some\some1\ABCD00000002
ABCD00000001,\some\some1\ABCD00000003
ABCD00000001,\some\some1\ABCD00000004
ABCD00000001,\some\some1\ABCD00000005
ABCD00000001,\some\some1\ABCD00000006,Y,,2