Re: Continuing While Loop One Iteration After EOF
by ikegami (Patriarch) on Dec 21, 2005 at 17:21 UTC
|
{
local $_;
do {
$_ = <INHANDLE>;
...
} while defined $_;
}
for (;;) { # Loop until "last".
local $_ = <INHANDLE>;
...
last if not defined $_;
}
{ # Loop while "redo".
local $_ = <INHANDLE>;
...
redo if defined $_;
}
my $block = sub { ... };
&$block while <INHANDLE>;
&$block foreach undef;
All of the snippets set $_ to undef on the last pass.
All of the snippets have access to the lexical variables, package variables and @_ of the parent scope.
Update: Moved local outside of the loop in first snippet.
| [reply] [d/l] [select] |
Re: Continuing While Loop One Iteration After EOF
by BrowserUk (Patriarch) on Dec 21, 2005 at 18:16 UTC
|
If you recognise that the body of the while loop is effectively a subroutine with implicit parameters, then it becomes natural to think of what you describe as (crudely):
doBody( $_ ) while( <FILEHANDLE> );
doBody( undef );
Which makes it clear that
- you are calling (some part(s) of) the body from two different locations;
- you want the body to take different actions dependent up when it is called;
Ie. When processing the file, or afterwards.
- Your "$_ == NULL" is a flag used just to decide when to do which type of processing.
That probably indicates that there is some subset of the processing inside the body of the loop that should really be factored into a separate subroutine, rather than inlined. Leading to
while( <FILEHANDLE> ) {
do some stuff;
doTheFactoredStuff();
do some other stuff;
}
doTheFactoredStuff();
Which may suggest a better way of doing things--or not:)
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
|
Thanks everyone for the replies. Functionally, the subroutine path does make good sense and probably should be the way to implement this. Procedurely, ikegami's earlier suggestion with the for(;;){} construct worked like a charm. Thanks again to all.
| [reply] [d/l] |
Re: Continuing While Loop One Iteration After EOF
by ruoso (Curate) on Dec 21, 2005 at 17:37 UTC
|
my $i = 1;
while ((my $line = <INHANDLE>) || $i--) {}
or, just what has been said here
while (my $line = <INHANDLE>) {
} continue {
dosomething() if eof(INHANDLE);
}
I would prefer the first, as the continue solution wouldn't enable the reuse of the while block.
| [reply] [d/l] [select] |
|
|
while (my $line = <INHANDLE>) {
...
} continue {
... if eof(INHANDLE);
}
is no different than
while (my $line = <INHANDLE>) {
...
}
...
(barring reading errors), so it's not very useful. The code will be duplicated, which seems to be what the OP wants to avoid. | [reply] [d/l] [select] |
|
|
| [reply] |
|
|
|
|
|
|
Re: Continuing While Loop One Iteration After EOF
by traveler (Parson) on Dec 21, 2005 at 19:58 UTC
|
while(( $_ = <INHANDLE>) || ($_ = 'AFTERFILE') ){
stuff;
}
Assuming, as you imply, that the body of the loop will know what to do when it sees AFTERFILE. | [reply] [d/l] [select] |
|
|
| [reply] [d/l] |
|
|
That will loop through the file, but then it will continue to loop forever with 'AFTERFILE' in $_. So if you're going to do that, you'd have to do it as
while (defined($_ = <INHANDLE>) || ($_ = "AFTERFILE")){
stuff;
last if $_ eq "AFTERFILE";
}
and of course, if the file actually contains AFTERFILE, you're in trouble.
So if you don't mind undef as your special after loop value, it's probably easiest to do something like
LOOP: {
$_ = <>;
stuff;
redo LOOP if defined;
}
| [reply] [d/l] [select] |
|
|
The OP suggested AFTERFILE and that's why I said "Assuming, as you imply, that the body of the loop will know what to do when it sees AFTERFILE."
| [reply] [d/l] [select] |
Re: Continuing While Loop One Iteration After EOF
by swampyankee (Parson) on Dec 21, 2005 at 17:13 UTC
|
What about continue?
Checkingthe perldocs (perldoc perlsyn; look for "continue"), it looks like it may be what you need.
| [reply] |
|
|
Good suggestion, but I don't think it fits the bill. continue is ran on each iteration - I just want to run the loop one last time, from the top, after the last line in the file is processed.
| [reply] [d/l] |
|
|
Then redo is just for that! Unfortunately you can't use it as simply as in
redo if eof;
since eof will continue to hold true and you won't run the loop just one last time. You'll have to add some more custom control instead:
my ($i,$cnt);
while (<$inhandle>) {
print ++$i;
last if $cnt;
$cnt++, redo if eof;
}
To add to the other suggestions you have been given and with a big caveat: we always recommend to always read files in line by line and not to slurp them in all at once. But if you're confident your input will not be exceedingly large in size and/or you collect all lines anyway, you may just do the latter:
for (<$infile>,'AFTERFILE') { ... }
| [reply] [d/l] [select] |