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

Hi everyone, used loads of answers on this from other peoples questions before but never asked a question... I have a foreach loop which the array holds line by line of a file. The file is being modified line by line to translate its format. Unfortunately the source file has changed format and now there are tables which run over multiple lines. What I want to do is:
foreach $line (@lines) { if ($line =~m/^SY /) { $line =~s/^SY/CN/) if (next =~m/^SY /) { next =~s/^SY/ /; } } } # so if the first line starts 'SY' replace with 'CN', but if the next +after the replacement does, then change SY on the next line for ' '.
I don't think 'next' can't be modified as a scalar though...any ideas? Cheers! Stevie

Replies are listed 'Best First'.
Re: Modifying 'next' in foreach loop
by kyle (Abbot) on Apr 28, 2008 at 14:49 UTC

    One way is to loop over the indices of the array rather than the array items.

    for( my $i = 0; $i <= $#lines; $i++ ) { if ( $lines[$i] =~ s/^SY(?= )/CN/ ) { if ( defined $lines[$i+1] ) { $lines[$i+1] =~ s/^SY(?= )/ /; } } }

    Another way is to join all the lines into one large string and do replacements.

    Still another way would be to use a flag variable to say when the previous line matched.

    my $previous_line_matched = 0; foreach my $line ( @lines ) { if ( $previous_line_matched ) { $line =~ s/^SY(?= )/ /; } if ( $line =~ s/^SY(?= )/CN/ ) { $previous_line_matched = 1; next; } $previous_line_matched = 0; }
      for( my $i = 0; $i <= $#lines; $i++ ) {

      would be better written:

      for my $i (0 .. $#lines) {

      Perl is environmentally friendly - it saves trees
Re: Modifying 'next' in foreach loop
by apl (Monsignor) on Apr 28, 2008 at 14:40 UTC
    Anal-retentive comments: I think you meant $next, not next. You forgot to show us how $next was set.

    Given the way you're processing the file, I think you need to include a state indicator.

    my $changed = 0; foreach $line (@lines) { if ($line =~m/^SY /) { if ( $changed == 0 ) { $line =~ s/^SY/CN/) $changed = 1; } else { $line =~ s/^SY/ /; $changed = 0; } } else { $changed = 0; } }
    There are terser ways of representing this, but I think this is readable. (It is untested, be warned!)
Re: Modifying 'next' in foreach loop
by runrig (Abbot) on Apr 28, 2008 at 16:01 UTC
    First, if ( $line =~ /^SY/ ) { s/^SY/CN/ } is redundant. And if you need to keep track of what the "next" line is, set a flag:
    my $is_sy; for my $line (@lines) { if ( $is_sy ) { $line =~ s/^SY/ /; $is_sy = 0; } else { $is_sy = ( $line =~ s/^SY/CN/ ); } }
Re: Modifying 'next' in foreach loop
by mscharrer (Hermit) on Apr 28, 2008 at 15:33 UTC
    next is a command which tells perl to jump to the next iteration of the loop - it doesn't return the next value of the loop - neither as rvalue (not changeable) nor as lvalue (changeable). So you mixed something completely up here. See the solution posted by the monks before me.