Beefy Boxes and Bandwidth Generously Provided by pair Networks
Keep It Simple, Stupid
 
PerlMonks  

Re^2: Win32::OLE Excel search and replace commas

by generator (Pilgrim)
on Oct 11, 2010 at 22:34 UTC ( [id://864709]=note: print w/replies, xml ) Need Help??


in reply to Re: Win32::OLE Excel search and replace commas
in thread Win32::OLE Excel search and replace commas

Thanks for the feedback. I didn't find a way to run a search and replace using OLE. (I was attempting to replicate the manual steps I took, while manually editing these files).

I did, however, find a solution. I extracted the cell values then ran a substitute =~ s/,//; on the scalar value before writing it to a text file, followed by a comma.

#!c:/perl/bin/perl.exe use strict; use warnings; use Win32::OLE qw(in with); use Win32::OLE::Const 'Microsoft Excel'; $Win32::OLE::Warn = 3; open (OUTPUT,">>","c:/assess/output.txt"); my $Excel = Win32::OLE->GetActiveObject ('Excel.Application') || Win32::OLE->new('Excel.Application', 'Quit'); my $Book = $Excel->Workbooks->Open ("C:/assess/assessment.xls"); my $Sheet = $Book->Worksheets(1); my $LastRow = $Sheet->UsedRange->Find({What=>"*", SearchDirection=>xlPrevious, SearchOrder=>xlByRows})->{Row}; my $array = $Sheet->Range("B2:"."F".$LastRow)->{'Value'}; foreach my $ref_array (@$array) { foreach my $scalar (@$ref_array) { $scalar =~ s/,//; print OUTPUT "$scalar,"; } print OUTPUT "\n"; } $Book->Close;

Your warning regarding the use of commas in formulas was wise but in this case irrelevant. The subsequent processing used only integer values associated with unit cost, unit rate and account code (text string). All fields with formulas are ignored.

Thanks again for taking the time to reply. It ain't pretty but it will do the job.

<><

generator

Replies are listed 'Best First'.
Re^3: Win32::OLE Excel search and replace commas
by davies (Prior) on Oct 12, 2010 at 06:56 UTC
    Ah, the joys of having code to look at. You're going to a lot of trouble to generate the CSV, when Excel will do it for you automatically.
    use strict; use warnings; use Win32::OLE; my $Excel=Win32::OLE->new('Excel.Application'); $Excel->{Visible}=1; $Excel->{DisplayAlerts}=0; my $Book = $Excel->Workbooks->Open("F:\\assess\\assessment.xls") or di +e "Can't open file"; $Book->SaveAs({Filename => "F:\\Assess\\Assessment.csv", FileFormat => 6, #xlCSV, CreateBackup => 0}); $Excel->Quit;
    A few points. First, indenting code within if blocks, loops etc. will make it easier for you to understand what your code is doing in a few months' time. Second, I commented in Re^3: Win32::Ole excel external data range on both with and relying on an existing instance of Excel. I suspect both you and the other OP copied code from the same place. Third, the thread I mentioned earlier describes dealing with embedded commas and quotes, but the general rule for CSVs is that you can embed a comma in quotes. The output of my test file is:
    1,2,3,4 2,"Who, What?",4,5 3,4,5,6 4,5,6,7
    Update:
    If, despite this, you really need to get rid of commas, the following code will remove commas from text:
    use strict; use warnings; use Win32::OLE; my $Excel=Win32::OLE->new('Excel.Application'); $Excel->{Visible}=1; my $Book = $Excel->Workbooks->Open("F:\\assess\\Lorem.xls") or die "Ca +n't open file"; $Excel->Cells->Replace({ What => ",", Replacement => ""});
    This won't get rid of formatting commas in numbers. To do that, you will need to change the formats. But from your code, you're looking at the underlying numbers anyway, rather than printing a file.
    End of update

    Regards,

    John Davies
      Thanks again for sticking with me on this. You are right about my taking the "long way" around to get my CSV file. As I stated in my original post I was trying to replicate the steps I took manually to accomplsh the same thing. Until your post, I could not find how to replicate the search and replace finding commas and replacing with nothing

      After playing with your suggestions (and your code) I noted that your use of the "FileFormat" in...

      $Book->SaveAs({Filename => "F:\\Assess\\Assessment.csv", FileFormat => 6, #xlCSV, CreateBackup => 0});
      ...cleaned up any (text) fields with commas in them -- my biggest problem.

      Can you tell me where I might find the various options for "FileFormat" documented? The documentation installed with the module on my Windows Active State Perl installation isn't very comprehensive. The best piece of guidance I've found on this module was online at http://www.tek-tips.com/faqs.cfm?fid=6715.

      After finding your second response (almost a month after you posted it), I revisited this project and extended it a little to correct for situations where users enter a 1 or 2 digit code where my accounting program will expect to find a three digit code with leading zeros. By formatting the range containing the codes before saving the file as CSV I can correct for that.

      My current version (still a work in progress), here...

      use strict; use warnings; use Win32::OLE; my $fildir = "./"; opendir DIR, $fildir; my @files = grep { /.xls/ } readdir(DIR); closedir DIR; foreach my $files (@files) { chomp $files; my $Excel=Win32::OLE->new('Excel.Application'); $Excel->{Visible}=0; $Excel->{DisplayAlerts}=0; my $Book = $Excel->Workbooks->Open("C:\\Monks\\$files") or die "Ca +n't open file"; my $sheet = $Book -> Worksheets(1); $sheet -> Range ('A:A') -> {NumberFormat} = "000"; my $nmlng = length $files; my $nwnam = substr ($files,0,($nmlng - 4)); $Book->SaveAs({Filename => "C:\\Monks\\$nwnam.csv", FileFormat => 6, #xlCSV, CreateBackup => 0}); unlink ($files); $Excel->Quit; }
      ...checks the current directory for any excel files and pulls them into an array. Then each entry in that array is pushed through the routine you provided and the export file is like named with the CSV extant.

      Typical excel data would look like:

      Code,PropertyName,Unit Count,Unit Cost, Total Cost, TypeAbbreviation, +Comments 1,First Account,5,10.00,50.00,cod,User text here 002,"Second Account, The",10,20.00,200.00,cod,More narrative 003,Third Account,5,20.00,100.00,cod,Another comment

      I've had no success finding a way to make the filepaths in the...

      my $Book = $Excel->Workbooks->Open("C:\\Monks\\$files") or die "Can't +open file";
      $Book->SaveAs({Filename => "C:\\Monks\\$nwnam.csv",
      ...sections dynamic. I tried "$files", "./$files" and "$fildir/$nwnam.csv" without success. Any ideas? It would be great if I could use the same code no matter where the user chooses to put the files as long at the compiled perl program is in the same directory with the excel workbooks.

      In my many google searches, many people suggest creating VB Macros in Excel then converting them to comparable statements in Win32::Ole. However I've not had any luck finding any beginner's tutorials or samples of how to do that. If you can suggest a source or process, I'd appreciate it.

      Thanks again. As a interested (but novice) Perl programmer, people like you and most of the other Monks who take the time to point the way are what keeps me from quitting in frustration.

      <><generator
        OK, let's try to deal with your issues in order.
        Can you tell me where I might find the various options for "FileFormat" documented? The documentation installed with the module on my Windows Active State Perl installation isn't very comprehensive.
        This is one of my pet peeves. Thank you for stroking it. Yes, the documentation is not what it should be. The VBA constants are documented here. My nose tells me that there's some way of importing them to Perl as named constants, but I haven't looked for or stumbled on it as yet. However, converting them to their actual values is trivial - start Excel, bring up the IDE (Alt-F11), go to the Immediate pane (Ctrl-G) and type in ?xlcsv or whichever you want (VBA doesn't care about case). It will return the value.

        ...checks the current directory for any excel files and pulls them into an array.
        I'm not ecstatic about this approach. Without suggesting that it won't work, I would tend to loop through the directory, checking each file in turn. The problem I have with your approach is that if the directory is shared, you are either blocking access to all files or risking a file being deleted or added between the start and end of the process. By handling files one at a time, the period in which this can happen is minimised.

        Googling for '"current directory" perl' got me this - I'd be interested to hear from anyone if this is a Good Thing. It returns the current path in Unix format, i.e. with slashes, not backslashes. Your code must compensate. You will normally have to use double backslashes so that Perl understands that you mean a backslash and not some control character.

        I've had no success finding a way to make the filepaths in the sections dynamic.
        I think this is down to the slashes and backslashes again.
        This gets me to the following code:
        use strict; use warnings; use Cwd; use Win32::OLE; my $ext = ".xls"; my $newext = ".csv"; my $Excel=Win32::OLE->new('Excel.Application'); $Excel->{Visible}=1; $Excel->{DisplayAlerts}=1; #Set to 0 when the code is working, but +keep at 1 while debugging. my $dir = getcwd; $dir =~ s/\//\\\\/g; #Sort out the slashes and backslashes opendir(DIR, $dir) or die "can't opendir $dir: $!"; #Cookbook recipe 9 +.5 while (defined(my $file = readdir(DIR))) { if ((!-d $file) and (substr($file, -length($ext)) eq $ext)) { +#Someone WILL call a directory something.xls. I have the scars. my $Book = $Excel->Workbooks->Open("$dir\\\\$file") or die "Ca +n't open file $dir\\\\$file"; my $sheet = $Book -> Worksheets(1); $sheet -> Range ('A:A') -> {NumberFormat} = "000"; #The next line is pretty explicit to try to make it clear +what's going on. $Book->SaveAs({Filename => $dir . "\\\\" . substr($file, 0 +, length($file) - length($ext)) . $newext, FileFormat => 6, #xlCSV, CreateBackup => 0}); $Book->Close; } } closedir(DIR); $Excel->Quit;
        I haven't tested it rigorously - I don't want to make dozens of files I don't need, especially as I do use CSVs - but I have tested most parts of it, and I think it will do what you need. If I have read the substr docs correctly, it can be used to change the extension directly, but that's beyond (a) me, (b) the scope of this lecture. :-)

        You mention needing the Perl and Excel files in the same directory. I don't find I need that. Provided the machine can find the Perl - either via the PATH or specified as part of the call on the command line - it will work no matter where the Perl code is. This I have tested.

        In my many google searches, many people suggest creating VB Macros in Excel then converting them to comparable statements in Win32::Ole. However I've not had any luck finding any beginner's tutorials or samples of how to do that.
        I'm not sure whether you mean writing VBA or converting it. As far as converting is concerned, this is the classic reference. For writing VBA, Googling "excel vba introduction" gives lots of places. I'm a Perl beginner but not an Excel beginner, so I can't really recommend any of them. "Excel $year Power Programming With VBA" by John Walkenbach is outstanding. It starts with baby steps and eventually gets seriously sophisticated.

        Regards,

        John Davies

        Update: deleted redundant relic line from code.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://864709]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others about the Monastery: (7)
As of 2024-04-18 22:15 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found