in reply to Re: Read from multiple files change the data with a script and the write the respective output files with a different extension
in thread Read from multiple files change the data with a script and the write the respective output files with a different extension

Thank you very much for your help, but after I turn my code into a function, I still can't figure out how to read all the files and replace the extension...I wrote something like this:

#!/usr/bin/perl use warnings; use strict; sub process_file { my ($original, $final) = @_; open( my $original_fh, "<", $original ) or die $!; open( my $final_fh, ">", $final ) or die $!; my $first = <$original_fh>; print $final_fh $first; my @replace = $first =~ /"([^"]*)"/g; while (my $line = <$original_fh>) { print "Enter the desired number of columns: "; my $nr = <STDIN>; chomp($nr); $line =~ s/((\w\w\t){$nr})/$1\n/g; $line =~ s/\t/,/g; $line =~ s/(\d{2})/$replace[$1]/g; print $final_fh $line; } close $original_fh; close $final_fh; } my @files = glob '*.txt'; my $new_file = $name =~ s/txt$/csv/r; process_file($files, $new_file);

but I know it can't run...I didn't quite understand how can I use the substitution that you wrote because I know that $name is not declared. I appreciate any advice you can give me!

  • Comment on Re^2: Read from multiple files change the data with a script and the write the respective output files with a different extension
  • Download Code

Replies are listed 'Best First'.
Re^3: Read from multiple files change the data with a script and the write the respective output files with a different extension
by hippo (Archbishop) on Oct 13, 2016 at 11:35 UTC

    You have many files and want to process one at a time, so use a loop:

    my @files = glob '*.txt'; for my $name (@files) { my $new_file = $name =~ s/txt$/csv/r; process_file($name, $new_file); }

      If you could help me with another problem I encountered in this program I would be very grateful. I want to enter the number of columns, only once for all the files, not for every file. My original code is:

      while (my $line = <$original_fh>) { print "Enter the desired number of columns: "; my $nr = <STDIN>; chomp($nr); $line =~ s/((\w\w\t){$nr})/$1\n/g; $line =~ s/\t/,/g; $line =~ s/(\d{2})/$replace[$1]/g; print $final_fh $line; }

      and I tried something like this unsuccessfully

      while (my $line = <$original_fh>) { for my $file (@files) { print "Enter the desired number of columns: "; my $nr = <STDIN>; chomp($nr); $line =~ s/((\w\w\t){$nr})/$1\n/g; } $line =~ s/\t/,/g; $line =~ s/(\d{2})/$replace[$1]/g; print $final_fh $line; }

        There are 2 key conceptual problems here.

        Firstly you reference @files in a location where it has not been declared. You need to consider scoping with regard to subs.

        Secondly, you have put your new code inside a for loop which is itself inside a while loop. Can you explain why you think this means it would only be executed once?

        Think about the flow of work in words. When you have something that make sense in words, you just need to translate it into Perl code.

        You say: "and I tried something like this unsuccessfully"

        while (my $line = <$original_fh>) { for my $file (@files) { print "Enter the desired number of columns: "; my $nr = <STDIN>; chomp($nr); $line =~ s/((\w\w\t){$nr})/$1\n/g; }

        If you translate this in plain english it sounds like: while is true that I can read a line from this file, for each file I have, ask me how many column I must consider. It does make no big sense.

        You want firstly ask how many column to consider, then for each file obtain the output filename, open it and foreach line do some transformation. Right?

        Now in plain english (if my english can be plain..) your overall program must resemble to something like this TODO list:

        • Fill @files using glob
        • decide how many column are desired (ask the user or hardcode in the program)
        • foreach @files compose the name of the output file ( my $new_file = $name =~ s/txt$/csv/r; ), open a new file in in write mode open( my $final_fh,    ">", $final )    or die $!; then open the source file for reading and foreach line make some transformation and write the line to the output file. When input file is finished, clean up ie close the pair of files and pass to next source one.
        When you have the basic flow of the program working you can add some brick here and there to make it more robust: what happen if I cant read? you yet added or die $! and this is good. What happen if an output file already exists?

        Notice also that a practical way to ask user for something can be accomplished in a cleaner and less verbose way giving your program the ability to parse command line arguments: two core module are devoted to such tasks: Getopt::Std that is basic and the more developped Getopt::Long

        HtH

        L*

        There are no rules, there are no thumbs..
        Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

      Thank you very much for your help. It's all clear now.