st4k has asked for the wisdom of the Perl Monks concerning the following question:

Im still a perl newbie so go easy ;-)
My question is how in the world do arrays get seperated?
Ive made up a test script to see how its done. I have 3 files with several words that I want to push into 1 large array while lowercasing each word but each file gets pushed up against the last without a newline. Output ends up like this and I cant figure out how to change this behavior:
one two threefour five sixseven eight nine
for (my $i = 0; $i < $num; $i++) { print "$ARGV[$i]\n"; open (FH, "$ARGV[$i]") || die "Cant open: $!"; while (<FH>) { push @out, lc; } close FH || die "Cant open: $!"; } print @out;
What am I doing wrong? :-(

Edit by ar0n -- added code tags

Replies are listed 'Best First'.
Re: I'm so confused
by jlongino (Parson) on Nov 24, 2001 at 07:13 UTC
    The problem is the way you have your data entered into the files. I can tell that your files look like this:
    file1:    file2:    file3:
    one\n     four\n    seven\n
    two\n     five\n    eight\n
    three^Z   six^Z     nine^Z
    The ^Z represent the end of file character. So that when you dump the array using:
    print @out;
    There are no line breaks between three-four and six-seven. To correct this you should chomp each read and store all the data without newlines:
    for (my $i = 0; $i < $num; $i++) { print "$ARGV[$i]\n"; open (FH, "$ARGV[$i]") || die "Cant open: $!"; while (<FH>) { chomp; ## <- added this line push @out, lc; } close FH || die "Cant open: $!"; }
    To print this as you would expect, use this instead:
    print join (@out,"\n");
    This tells print to make one long string with a newline inserted between each element of @out.

    Hope this helps.


      This place rocks! I didnt expect such prompt replies :-)
      The thing is I want each element in the array to be seperated by newlines so that when the script outputs the final list it will be nice and orderly, one word per line.
      What the script does is read from @argv some files that it will read into an array, lowercase, sort, remove dups (not done yet) and then output the final array to out.txt
      Is there a way to "unchomp" an array making sure that each element has a newline (but not add one if it already does) or something like that?
      Thanks to everyone who replied
      Im reading also while Im trying everyones ideas
      #!/usr/bin/perl use strict; use warnings; use diagnostics; my @out; my $num = scalar(@ARGV); if (-e "out.txt"){ print "Please move or rename out.txt\n"; exit 0; } for (my $i = 0; $i < $num; $i++) { open (FH, "$ARGV[$i]") || die "Cant open: $!"; while (<FH>) { push (@out, lc); } close FH || die "Cant close: $!"; } print sort @out
        You might want to be using the <> operator here. <> reads from the files passed in ARGV (if they exist) or from STDIN otherwise. This means that you can have this behaviour with no extra effort if you want it in the future.

        It'll certainly save you from having to worry about opening each of those files and the like. So your code could simplify to:

        #!/usr/bin/perl -w use strict; use diagnostics; if(-e "out.txt") { # complain about file. } my @out; while(<>) { chomp; push @out, lc($_); } # do stuff with @out: @out = sort @out; # print it (to STDOUT for the moment) print join("\n", @out);
        I agree with everyone else here, that you probably don't want to be inserting the newline until you're ready to output the data. If you decide, for some reason, later to reverse all the characters on each of your lines or some such, that newline character can get in the way.

        Good luck.

        Generally speaking, you're not going to want new lines in your actual data. That may not always be the case, but if you're going to work with what's in the array, the new line char might get in the way. The best way (in my opinion), would be to chomp off the new line char, and then when you output it, print new lines. There's several ways to do that. The easiest way would be to take the array and join all elements together with new lines. like so..
        print join "\n", @out;
        Hope that helps,
        Hey the join function works but not in the way I expected it to work.
        print join "\n", @out;
        works just fine and inserts the newline seperator just like I want it to do while
        join "\n", @out;
        print @out;
        returns the chompd output
        the solution I figured out was
        @out = join "\n", @out;
        print @out;
        Is this the correct way to do this? Im trying to be as strict as possible and learn perl without using cheats and workarounds if you know what I mean. If I get the hang of properly structured programming I think it can cary over to whatever language I learn in the future. THANKS AGAIN EVERYONE!
Re: I'm so confused
by the_0ne (Pilgrim) on Nov 24, 2001 at 07:07 UTC
    It looks like what's happening is line one and two have newlines (\n) and three doesn't. Same with four and five. So, if you really do want the newlines in each instance of the array, then you should probably do this...
    while (<FH>) { chomp; push @out, lc("$_\n"); }
    If you do not want the newlines in each instance of the array, then just use the chomp.

    Unless I'm totally misunderstanding, that should take care of your problem.
Re: I'm so confused
by davorg (Chancellor) on Nov 24, 2001 at 14:22 UTC

    You values are being stored in the array exactly how you want them. The problem you are seeing comes simply in the output stage.

    When you print out an array using code like:

    print @out;

    All the elements in the array are printed out with nothing between them. You can change this default behaviour by changing the value in $,. Perl prints the value of this variable inbetween the elements of an array. For example:

    { local $, = ':'; print @out; }

    This prints the array elements separated with colons. Notice that I've localised the change to $, by putting it in a naked block. This is good practice for whenever you change the value of one of Perl's special variables.

    Another technique you could use is to print the array in a double quoted dtring like this:

    print "@out";

    In this case, the default is to print the values separated by spaces. Once again this behaviour can be changed. In this case you need to chages the value of the $" variable, like this:

    { local $" = "\n"; print "@out"; }

    In this case, the elements of @out will be separated by newline characters.


    "The first rule of Perl club is you don't talk about Perl club."

Re: I'm so confused
by George_Sherston (Vicar) on Nov 24, 2001 at 07:00 UTC
    Using the SOPW::Psychic module I think the answer to your question is to push a carriage return into @out after each time round your for loop.

    If that doesn't fix it, then post some more code... like what's in $num, what's the stuff that you're opening look like exactly...? etc etc. It's free! Post the whole script! A thing I've learnt about posting here is that often it's the thing I thought was irrelevant and left out that turns out to be the place eagle-eyed monks find my trouble.

    George Sherston