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

Dear Monks, I am new to perl and still learning the ropes. I am trying to use the foreach loop but not getting the desired output. Here's my code: use warnings;
print "Please enter the cns file:\n"; chomp($t=<STDIN>); open(THE,$t) or die "Can not open file: $!\n"; @data=<THE>; close THE; $sequence=''; $end=0; foreach $line(@data){ if($line=~/^\@/){ $chro=$line; }elsif($line=~/^[a-zA-Z]/){ $sequence.=$line; }else{ $end++ } } $sequence=~s/\s*$//g; print $chro,"\n"; print $sequence,"\n";
The file am reading in looks like this: <@chr1 nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn @chr2 nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn nnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn> My problem is this will only output the last iteration i.e @chr2 followed by the nnnn's. How can I make it return the file the way it looks like from the input i.e. @chr1 nnnn.. followed by @chr2 nnn....? thanks.

Replies are listed 'Best First'.
Re: foreach loop
by wind (Priest) on May 04, 2011 at 16:23 UTC

    As documented in How do I post a question effectively?, please enclose your code in <code> tags so that people can read it:

    <code>
    ... your code here ...
    </code>

    Here's your code run through Perl::Tidy so that anyone else can help more easily:

    use warnings; print "Please enter the cns file:\n"; chomp($t = <STDIN>); open(THE, $t) or die "Can not open file: $!\n"; @data = <THE>; close THE; $sequence = ''; $end = 0; foreach $line (@data) { if ($line =~ /^\@/) { $chro = $line; } elsif ($line =~ /^[a-zA-Z]/) { $sequence .= $line; } else { $end++ } } $sequence =~ s/\s*$//g; print $chro, "\n"; print $sequence, "\n";
      the brackets are there I don't know why they didn't show in the post.

        Because you didn't put <code>...</code> tags around your code, and brackets have a special meaning here (for creating links). Please do that now, you can update your original post.

Re: foreach loop
by ikegami (Patriarch) on May 04, 2011 at 16:56 UTC
    if ($line =~ /^\@/) { print $chro,"\n" if length $chro; $chro = $line; }
      thanks for that. However, adding this line to my code only outputs:
      @chr1 @chr2 nnnnn... what I'd really like to have is: @chr1 nnnnnnnnn... @chr2 nnnnn....

        This uses ikegami's approach; this will print the previous $chro as soon as a new '@' is found. You seem to want to print $sequence at the same time. This moves the print statements inside the loop. Also, you need to reset sequence after the new @ is found. If you would give us something more detailed than 'nnnn' we could see where things should go. Try using __DATA__ next time to hold some sample data for everyone to see.

        use warnings; use strict; print "Using __DATA__ sample cns file:\n"; #chomp($t = <STDIN>); #open(THE, $t) or die "Can not open file: $!\n"; #@data = <THE>; my @data = <DATA>; #close THE; my $sequence=""; my $chro; foreach my $line (@data) { if ($line =~ /^\@/) { print $chro if length $chro; $chro = $line; print $sequence; $sequence = ""; } elsif ($line =~ /^[a-zA-Z]/) { $sequence .= $line; } else { print "no match: \$line=$line\n" } } #prints the last one, I'm sure theres a better way print $chro if length $chro; print $sequence,"\n"; __DATA__ @chr1 ACAAGATGCCATTGTCCCCCGGCCTCCTGCTGCTGCTGCTCTCCGGGGCCACGGCCACCGCTGCCCTGCC CCTGGAGGGTGGCCCCACCGGCCGAGACAGCGAGCATATGCAGGAAGCGGCAGGAATAAGGAAAAGCAGC @chr2 CTCCTGACTTTCCTCGCTTGGTGGTTTGAGTGGACCTCCCAGGCCAGTGCCGGGCCCCTCATAGGAGAGG AAGCTCGGGAGGTGGCCAGGCGGCAGGAAGGCGCACCCCCCCAGCAATCCGCGCGCCGGGACAGAATGCC @chr55 CTGCAGGAACTTCTTCTGGAAGACCTTCTCCTCCTGCAAATAAAACCTCACCCATGAATGCTCACGCAAG

        Update: would be better to replace the foreach with while (my $line=<DATA>) and get rid of @data. Especially since the files will probably be large.