How does one move down a line in a file?

Discussion in 'Perl Misc' started by John, Oct 14, 2003.

  1. John

    John Guest

    I'd like to move down a file and assign each line to a different variable.
    How can I skip/move forward a line within the following while loop?

    while (<FILE>) {
    first = $_;
    second = $_;
    third = $_;
    }

    # all below vars have different values
    print $first;
    print $second;
    print $third;


    Thanks
     
    John, Oct 14, 2003
    #1
    1. Advertisements

  2. John

    Anno Siegel Guest

    I'm pretty sure you don't really want to do that. How would you access the
    last line of a file of 1234 lines? $one_thousand_two_hundred_thirty_fourth?

    You *may* want to assign the lines to an array with each line in one
    position.
    First off, you forgot the "$"s in front of your variables. A quick test
    (perl -c) would have shown your error. If you post code, please make
    sure it is syntactically correct.

    Otherwise, the code doesn't do in the least what you want. It assigns
    the *same* line (in $_) into $first, $second and $third. Then, in the
    next iteration, it overwrites the values with the next line. You end
    up with the last line of the file in all three variables.

    With an array the solution looks like this:

    my @list;
    while (<FILE>) {
    push @list, $_;
    }

    or just

    print $list[ $_] for 0 .. 2;

    Anno
     
    Anno Siegel, Oct 14, 2003
    #2
    1. Advertisements

  3. John

    Anno Siegel Guest

    Ah... you probably understood the OPs intention better than I did
    in another reply.

    The "err" operator looks interesting. How is it specified?

    Anno
     
    Anno Siegel, Oct 14, 2003
    #3
  4. John

    John Guest

    Thanks Anno. I actually changed to an array solution and it works as I
    needed it in a much neater way:
    open(FILE, $file);
    @lines = <FILE>;
    close(FILE);
     
    John, Oct 14, 2003
    #4

  5. By simply reading from the file:

    if ( want_to_skip_line() ) {
    <FILE>; # read and discard line
    }
     
    Tad McClellan, Oct 14, 2003
    #5
  6. John

    Helgi Briem Guest

    Don't do that. Use a hash instead:

    #!perl
    use warnings;
    use strict;
    my %line;
    while (<DATA>)
    {
    $line{$.}= $_;
    }

    # Have a look at the contents of %line
    for (sort { $a <=> $b } keys %line)
    {
    print "$_\t$line{$_}";
    }
     
    Helgi Briem, Oct 14, 2003
    #6
  7. [ snip full-quote. Please do not do that. ]


    You should always, yes *always*, check the return value from open():

    open(FILE, $file) or die "could not open '$file' $!";
     
    Tad McClellan, Oct 14, 2003
    #7
  8. -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    You would do the above instead of

    @line = <DATA>;

    for ($i=0; $i<@line; $i++)
    {
    print "$i\t$line[$i]";
    }

    ?

    - --
    Eric
    $_ = reverse sort $ /. r , qw p ekca lre uJ reh
    ts p , map $ _. $ " , qw e p h tona e and print

    -----BEGIN PGP SIGNATURE-----
    Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

    iQA/AwUBP4v/jmPeouIeTNHoEQLQ4wCeNNGVhWyUvgPgSo2U6yhiYTogMo4An35P
    4SOlnDyTHapWOcgjYeO+5wdD
    =Tpwh
    -----END PGP SIGNATURE-----
     
    Eric J. Roode, Oct 14, 2003
    #8
  9. John

    Anno Siegel Guest

    Ah, very nice. Compiling...

    Anno
     
    Anno Siegel, Oct 14, 2003
    #9
  10. John

    Anno Siegel Guest

    Why that instead of

    print "$_\t$line[$_]" for 0 .. $#line;

    :)

    Anno
     
    Anno Siegel, Oct 14, 2003
    #10
  11. --untested--
    while(<FILE>){
    my $first = <FILE>;
    my $second = <FILE>;
    my $third = <FILE>;
    last;
    }
    --untested--

    This will get the first three lines - 'last' breaks the loop.

    HTH

    --
    Jim

    Copyright notice: all code written by the author in this post is
    released under the GPL. http://www.gnu.org/licenses/gpl.txt
    for more information.

    a fortune quote ...
    Eat drink and be merry, for tomorrow they may make it illegal.
     
    James Willmore, Oct 14, 2003
    #11
  12. John

    Anno Siegel Guest

    Indeed...

    It drops the first line and reads the next three. It will also read
    past eof if there are fewer than four lines. That raises the question
    why "while" is there at all.

    See Abigail's solution for a correct one. (If only the first three
    lines are wanted, omit "redo" from Abigail's code.)

    Anno
     
    Anno Siegel, Oct 14, 2003
    #12
  13. That will get the 2nd, 3rd and 4th lines into $first, $second and $third
    respectively. Because they are my variables, they will be lost as soon
    as you exit the while loop.
     
    Glenn Jackman, Oct 14, 2003
    #13
  14. -----BEGIN PGP SIGNED MESSAGE-----
    Hash: SHA1

    -berlin.de (Anno Siegel) wrote in @mamenchi.zrz.TU-Berlin.DE:
    Because I wanted to duplicate Helgi's structure as much as possible.
    Mostly I was surprised that he would represent the lines of the file as a
    hash instead of an array.

    - --
    Eric
    $_ = reverse sort $ /. r , qw p ekca lre uJ reh
    ts p , map $ _. $ " , qw e p h tona e and print

    -----BEGIN PGP SIGNATURE-----
    Version: PGPfreeware 7.0.3 for non-commercial use <http://www.pgp.com>

    iQA/AwUBP4xUBWPeouIeTNHoEQJkIACbBL+eE4OIk9jTVoUStB9NMwlV/IIAoNfC
    Lh4pjqULQrydXIbpUPLzu+DM
    =5Jpi
    -----END PGP SIGNATURE-----
     
    Eric J. Roode, Oct 14, 2003
    #14
  15. John

    John Guest

    wow, so many answers :)

    can some1 pls elaborate why the variables start getting values from the 2nd
    line instead of the 1st one?
    what happens to the first line? goes into a void?
     
    John, Oct 15, 2003
    #15

  16. This construct:
    while (<FILE>) {...}
    sets $_ each time through the loop. So the first line is stored in $_,
    which will remain after the while loop ends.

    The perlop man page says:

    The following lines are equivalent:

    while (defined($_ = <STDIN>)) { print; }
    while ($_ = <STDIN>) { print; }
    while (<STDIN>) { print; }
    for (;<STDIN>;) { print; }
    print while defined($_ = <STDIN>);
    print while ($_ = <STDIN>);
    print while <STDIN>;

    This also behaves similarly, but avoids $_ :

    while (my $line = <STDIN>) { print $line }


    I've forgotten your original question. If it was how to read a file 3
    lines at a time, you could write:

    while (my $one = <FILE>) {
    my $two = <FILE>;
    my $three = <FILE>;
    # do something with $one, $two, $three.
    # $two and $three may be undefined.
    }
     
    Glenn Jackman, Oct 15, 2003
    #16
  17. John

    Roy Johnson Guest

    No, it goes into $_. What did you think the "while(<FILE>)" line is
    doing?

    Each time you use the <> operator, you grab a new line. Your original
    example put the same grabbed line into each variable. The example
    above has four reads, and the first one is basically ignored.

    Reading the whole thing into an array (as suggested by Eric Roode) may
    be your most straightforward bet, depending on what you are really
    trying to do.

    Here's a variation on Abigail's recommendation for getting lines into
    three variables:

    READLOOP:{
    defined($_=<DATA>) or last READLOOP for (my ($v1, $v2, $v3));

    # Process lines here

    redo;
    }
     
    Roy Johnson, Oct 15, 2003
    #17
  18. --untested--
    my($first,$second,$third);
    while(<FILE>){
    $first = <FILE>;
    $second = <FILE>;
    $third = <FILE>;
    last;
    }
    --untested--

    -or-

    --untested--
    my($first,$second,$third);
    my $count = 1;
    while(<FILE>){
    $first = <FILE> if $count == 1;
    $second = <FILE> if $count == 2;
    $third = <FILE> if $count == 3;
    last if $count == 4;
    }
    --untested--

    -or-

    --untested--
    my($first,$second,$third);
    while(<FILE>){
    $first = <FILE> if $. == 1;
    $second = <FILE> if $. == 2;
    $third = <FILE> if $. == 3;
    last if $. == 4;
    }
    --untested--

    -or-

    --untested--
    my @lines = <FILE>;
    #access each ine as an element of the array
    --untested--

    -or-

    use one of the _many_ Perl modules relating to files.

    This question is a bit like "How do I print a formated line?". The
    accepted/first method is to use 'printf'. However, depending on what
    the end result is supposed to be and what else needs to be done and
    how the output is _supposed_ to look, you could use 'format'. Or, you
    could use 'sprintf' to format the string first, then use'print' to
    print the line (now containing the formated string).

    Try writing out what you want to do on paper _first_. The answer
    _may_ just pop off the page at you.

    HTH

    --
    Jim

    Copyright notice: all code written by the author in this post is
    released under the GPL. http://www.gnu.org/licenses/gpl.txt
    for more information.

    a fortune quote ...
    Whistler's Law: You never know who is right, but you always know
    who is in charge.
     
    James Willmore, Oct 15, 2003
    #18
  19. John

    Roy Johnson Guest

    You're still getting the first line into $_, for no apparent reason.
    You might consider
    until(eof FILE)
    instead of
    Or, since you're breaking out of the loop on the first pass, just
    don't have a loop.
    You need to increment $count each time, or you're going to repeatedly
    assign $_ and $first, and none of the others. Is it not possible for
    you to test the solutions you propose?
    That's a winner, at least.
     
    Roy Johnson, Oct 15, 2003
    #19
  20. John

    John Guest

    No, it goes into $_. What did you think the "while(<FILE>)" line is
    doing?

    Each time you use the <> operator, you grab a new line. Your original
    example put the same grabbed line into each variable. The example
    above has four reads, and the first one is basically ignored.

    Reading the whole thing into an array (as suggested by Eric Roode) may
    be your most straightforward bet, depending on what you are really
    trying to do.

    Here's a variation on Abigail's recommendation for getting lines into
    three variables:

    READLOOP:{
    defined($_=<DATA>) or last READLOOP for (my ($v1, $v2, $v3));

    # Process lines here

    redo;
    }[/QUOTE]

    Roy and Glen,
    Thanks once again :)
     
    John, Oct 16, 2003
    #20
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.