Edward WIJAYA wrote:
Hi,

Hello,

I have a simple code that take
currently fixed to take 3 input files and
append each line of these files together.

I wish to know is there anyway I can
write the code more flexibly so it can
dynamically take the input argument - from minimum
2 files to more.

Is there anywhere I can find information
about dealing with this matter? Any specific
module that cater this problem?

You could use the paste program to do that.

man paste


This is my current (terribly inefficient
and unflexible) code:

#!/usr/bin/perl -w
use strict;
use Data::Dumper;


if(scalar @ARGV ne 1)

You are using 'ne' which compares strings when you should be using '!=' which is used to compare numbers. Both the comparison operator and the if conditional force scalar context so using 'scalar' is redundant.


if ( @ARGV != 1 )

However that only works if the command line has exactly one filename and you want to require two or more.

if ( @ARGV >= 2 )


{
    print "Usage: $0 file1 file2 [file3] etc\n";
    exit(1);
}
#the above part doesn't seem to be working well/useful

my $file1 = $ARGV[0];
my @set1 = get_file_data("$file1");
                           ^^^^^^^^
perldoc -q quoting

Found in /usr/lib/perl5/5.8.2/pod/perlfaq4.pod
       What's wrong with always quoting "$vars"?


#Remove the whitspace and \n from each lines
@set1 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set1;
my $s1 = [EMAIL PROTECTED];

my $file2 = $ARGV[1];
my @set2     = get_file_data("$file2");
@set2 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set2;
my $s2 = [EMAIL PROTECTED];

my $file3 = $ARGV[2];
my @set3     = get_file_data("$file3");
@set3 = grep { s/^\s+//; s/\s+$//; s/\s+/ /g; length } @set3;
my $s3 = [EMAIL PROTECTED];



#Printout the appended lines from the data
print map { join("",$set1[$_],$set2[$_],$set3[$_]), "\n" } (0..$#set1);



#Subroutine
sub get_file_data {

    my ($filename) = @_;

    use strict;
    use warnings;

use() keeps track of which modules have been loaded so use()ing the same module more than once will not incur more overhead and will not do anything useful either.



    # Initialize variables
    my @filedata = ();

my() creates a lexical variable in an undefined state so assigning an undefined value to it is redundant.



    unless ( open( GET_FILE_DATA, $filename ) ) {
        print STDERR "Cannot open file \"$filename\"\n\n";

You should include the $! (or $^E) variable in the error message so you know why open() failed.



        exit;
    }

    @filedata = <GET_FILE_DATA>;
    close GET_FILE_DATA;
    return (@filedata);

If you had used a lexical filehandle you could have skipped the assignment to an array.



}

___END____

A valid __END__ token has two underscore characters before and after 'END'.


You have two basic options for merging files, store all the contents in memory which may run out of memory, or read each file line by line which may run out of file handles.


If the aggregate data will fit in memory you can do this:

#!/usr/bin/perl
use warnings;
use strict;

my ( $line, @data );
while ( <> ) {
    $data[ $line++ ] .= $_ if /\S/;
    $line = 0 if eof;
    }

# clean up whitespace
for ( @data ) {
    s/^\s+//;
    s/\s+/ /g;
    s/ $/\n/;
    }

print @data;

__END__


And if you need to read each file a line at a time you could do something like this:


#!/usr/bin/perl
use warnings;
use strict;

my @fhs = map { open my $fh, '<', $_ or die "$_: $!"; $fh } @ARGV;

while ( @fhs ) {
    my $line = '';
    for ( @fhs ) {
        defined( my $curr = <$_> ) or next;
        redo unless $curr =~ /\S/;
        $line .= $curr;
        }

    for ( $line ) {
        s/^\s+//;
        s/\s+/ /g;
        s/ $/\n/;
        }

    print $line;
    @fhs = grep !eof( $_ ), @fhs;
    }

__END__



John
--
use Perl;
program
fulfillment

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>




Reply via email to