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

Oh Great Monks, I have been crawling up a wall here on this, and can't seem to find a definitive answer via web searching. Does a foreach loop automatically add a newline to every value? And if so, why isn't chomp working? For example, if I do the following:
open (EVENTS_FILE, 't1Vevents.txt'); @EVENT_ARRAY = <EVENTS_FILE>; close (EVENTS_FILE); foreach $event_line (@EVENT_ARRAY) { chomp; if ($event_line =~ m/\s*d1/i) { ($d1_title,$d1_value) = split(/:/,$event_line); } if ($event_line =~ m/\s*d2/i) { ($d2_title,$d2_value) = split(/:/,$event_line); } if ($event_line =~ m/\s*d4/i) { @array = (@array,$d1_value,$d2_value); } } print @array;
my expected output would be
v1v2 v1v2
however, what I get is
v1 v2 v1 v2
I have tried chomp-ing on $event_line, and on @EVENT_ARRAY and @alarm_array, and on $d1_value and $d2_value but none of them seem to have the desired effect.

Thanks for the assistance!!

Replies are listed 'Best First'.
Re: foreach - adding newlines?
by ikegami (Patriarch) on Feb 09, 2009 at 20:25 UTC

    Ignoring your question for a second,

    chomp;

    should be

    chomp($event_line); # in the loop

    or

    chomp(@EVENT_ARRAY); # outside the loop

    Chomping $_ repeatedly are you are doing is useless since you never use $_.

    Back to your question, the only ways to get the output you describe from the code you posted is if:

    • if the value of $, contains a newline.
    • if the value of $/ isn't a newline.

    Would you care to add the following to the end of the code you posted and provide us the output?

    { use Data::Dumper; print(Data::Dumper->new( [ $,, $", $\, $/, \@EVENT_ARRAY, \@array, ], [ '$,', qw( $" $\ $/ $EVENT_ARRAY $array )] )->Useqq(1)->Dump()); }

    Update: Fixed bad D::D syntax

      Hrrm - coping the data dumper code results in an error: Usage: PACKAGE->new(ARRAYREF, ARRAYREF) at ./22.pl line 70

        Try this instead:

        { use Data::Dumper; print(Data::Dumper->new( [ $,, $", $\, $/, \@EVENT_ARRAY, \@array, ], [qw( $, $" $\ $/ $EVENT_ARRAY $array )] )->Useqq(1)->Dump()); }

        Update: (cf. johngg's reply) I suggested to move the parameters from Dump() to new() — otherwise I left ikegami's code as is. For reference, the original code was:

        { use Data::Dumper; print(Data::Dumper->new()->Useqq(1)->Dump( [ $,, $", $\, $/, \@EVENT_ARRAY, \@array, ], [qw( $, $" $\ $/ $EVENT_ARRAY $array )] )); }
      You're not ignoring the OP's question...the wrong thing is being chomp'd and that's the source of the problem :-)
        As I mentioned in the OP, I've tried chomp-ing various things in various places - is there somewhere specifically you would recommend? I'm open to try anything.
        Tnx
        Improper chomping doesn't explain the presence of a new line between v1 and v2.
Re: foreach - adding newlines?
by jwkrahn (Abbot) on Feb 09, 2009 at 20:19 UTC

    You should run your program with the warnings and strict pragmas enabled to let perl help you find mistakes.

    open (EVENTS_FILE, 't1Vevents.txt');

    You should always verify that the file opened correctly:

    open EVENTS_FILE, '<', 't1Vevents.txt' or die "Cannot open 't1Vevents. +txt' $!";

    @EVENT_ARRAY = <EVENTS_FILE>;

    You could chomp your array elements here if you like:

    chomp( my @EVENT_ARRAY = <EVENTS_FILE> );
    But do you really need to read the whole file into memory?

    foreach $event_line (@EVENT_ARRAY) { chomp;
    foreach my $event_line ( @EVENT_ARRAY ) { chomp $event_line;
    if ($event_line =~ m/\s*d1/i)

    The  \s* at the beginning of the pattern is superfluous because it matches zero characters.

    @array = (@array,$d1_value,$d2_value);

    That is usually, and more efficiently, written as:

    push @array, $d1_value, $d2_value;

    So, in summary, you want code more like this:

    use warnings; use strict; open EVENTS_FILE, '<', 't1Vevents.txt' or die "Cannot open 't1Vevents. +txt' $!"; my ( @array, %values ); while ( <EVENTS_FILE> ) { chomp; if ( /([dD][12])/ ) { $values{ lc $1 } = ( split /:/ )[ 1 ]; } if ( /[dD]4/ ) { push @array, @values{ 'd1', 'd2' }; } } close EVENTS_FILE; print @array;
Re: foreach - adding newlines?
by almut (Canon) on Feb 09, 2009 at 20:11 UTC

    Just a little nitpick (nothing to do with your problem).  In Perl,

    @array = (@array,$d1_value,$d2_value);

    would typically be written as

    push @array, $d1_value, $d2_value;
Re: foreach - adding newlines?
by GrandFather (Saint) on Feb 09, 2009 at 21:50 UTC

    The keys issue is that chomp was chomping the default variable ($_). Most likely if you had used strictures (use strict; use warnings;) you'd have received warnings about chomping an undefined value. added: The other part of the sting is that your "push" adds two entries to the array where you really need one entry that is the concatenation of the two value strings.

    However, there is some scope for a little tidying of your code. Consider:

    use strict; use warnings; my $events = <<'END_EVENTS'; d1:v1 d2:v2 d4:v4 d1:v1 d2:v2 d4:v4 END_EVENTS open my $eventsIn, '<', \$events or die "Failed to open event file: $! +"; my $d2_value; my $d1_value; my @eventList; while (<$eventsIn>) { chomp; my $title; if (m/d1/i) { ($title, $d1_value) = split /:/; } elsif (m/d2/i) { ($title, $d2_value) = split /:/; } elsif (m/d4/i) { push @eventList, "$d1_value$d2_value\n"; } } close $eventsIn; print @eventList;

    Prints:

    v1v2 v1v2

    Don't worry about the $event stuff - that's just to make a stand alone example without needing an external file.

    Note the use of the three parameter open and the use of 'or die' to check the result and report errors. Use a lexical file handle ($eventsIn) rather than a bare word file handle (EVENTS_IN).

    Use a while loop and handle things line by line. This code makes an end run around your chomp issue by actually using the default variable ($_) to store the line just read.

    Declare variables in the smallest scope you can - $title is only used inside the loop so that is where it is declared. The other variables require a lifetime that is longer than one loop iteration so they are declared outside the loop.

    To achieve the output you want you need to concatenate your two value strings and push the result. Your original code effectively pushed the two values into the array - you could do it that way, but printing becomes messy.

    The current code is likely to fail in nasty ways if the input data is not exactly as you expect it to be. You should think hard about better validation techniques!


    Perl's payment curve coincides with its learning curve.
Re: foreach - adding newlines?
by MidLifeXis (Monsignor) on Feb 09, 2009 at 19:50 UTC

    Could you perhaps give an example of your input? What type of machine is the data file generated on? What type of line endings are on the data file? What line endings are expected by the script ($/ variable)? Is binmode set?

    Update: I missed the same thing as FunkyMonk. Unstruck my response.

    --MidLifeXis

Re: foreach - adding newlines?
by hbm (Hermit) on Feb 09, 2009 at 20:03 UTC

    Did you set $/ to undef or empty? If so, you might want to wrap it, plus the open, slurp, and close in {} to localize it. Otherwise, bare chomps that follow are affected.

    And perhaps you want @EVENT_ARRAY = split/\n/,<EVENTS_FILE>;, to put each line into the array, rather than all the lines in one element?

Re: foreach - adding newlines?
by FunkyMonk (Bishop) on Feb 09, 2009 at 19:48 UTC
    Try chomp $event_line instead of plain chomp. The latter chomps $_.

    I missed the bit where you said you'd tried this. Sorry about that.

Re: foreach - adding newlines?
by nitehawk (Initiate) on Feb 09, 2009 at 20:31 UTC
    The input file was created on a unix system, there doesn't seem to be any errant newlines introduced (everything is done locally on my workstation - there isn't any ftp-ing, and I've created most using plain 'ol vi)
    $/ isn't set to anything explicitly - my understanding is that should default to \n, although I'll be more than willing to try it (although I can't seem to figure out how to do that offhand)
    I tried adding the split on the @EVENT_ARRAY line, and the script outputs nothing, blank. Thanks for the quick responses...
      On the command line, what output do you get when you do:
      perl -lne 'print "Got CR" and last if /\r/' t1Vevents.txt

      Do you see "Got CR" printed?
Re: foreach - adding newlines?
by nitehawk (Initiate) on Feb 11, 2009 at 19:31 UTC
    I've finally managed to figure out what was going on. Turns out that the file had CRs on _some_ of the lines. That was accounting for the weird behavior that chomp was working only some of the time. Looking at my logs, I must have created the file on a windows machine at work when I was originally working with this. Since the original file was worked on by various scripts before getting to the one I was working with now, I lost track of where it was created. This is why y'all are the monks, and I'm still re-learning :-) Thanks so much for the help!!