Re: Can this If/Else be condensed into a 1 liner with a trailing If?
by pjf (Curate) on Oct 02, 2001 at 07:57 UTC
|
Oh good, I'm glad you posted this. I had to take a phone-call while it was being discussed on the chatterbox, and when I came back the conversation had cleared.
Firstly your regexp will match anything which has a digit it in somewhere. This might not be what you want. Perhaps something like /^\s*(\d+)\s*$/ would be better, to require a sequence of digits with possible whitespace on either side. This leaves your number in $1 afterwards.
Secondly, think twice about having your input function call your input function. You could end up with a very large call stack here, killing performance and chewing memory.
I would suggest you use a loop like this:
while (defined($_ = <STDIN>)) {
print "Numbers only please" and next unless (/^\s*(\d+)\s*$/);
return $1;
}
die "urk! Out of input.\n";
This keeps reading from STDIN until we get a number (in which case we return it), or we run out of input. Plus there's no recusion involved, which is much better than calling ourselves repeatedly.
It's not a single line, but it probably does what you want, and is shorter than the original code.
Cheers,
Paul | [reply] [d/l] |
|
|
| [reply] [d/l] |
|
|
while (defined($_ = <STDIN>))
exactly the same as:
while(<STDIN>)
in perl 5.005 and above?
I remember a time when they *weren't* the same, but I'm pretty sure that they are now.
-Blake
| [reply] [d/l] [select] |
|
|
Well spotted, and quite correct. When dealing with numbers I tend to step to a higher level of paranoia, simply because zero is a number, but it's not true. This paranoia occasionally wears off onto the code around it. ;)
Cheers,
Paul
| [reply] |
|
|
|
|
|
Re: Can this If/Else be condensed into a 1 liner with a trailing If?
by lestrrat (Deacon) on Oct 02, 2001 at 07:59 UTC
|
Ah! potential inifinite recursion! bad! bad! Use a loop, not a recursion!
I was going to write an example code, but I don't understand what you want to do... you might want to clarify the following:
- What do you mean by "chomps only digits"?
- What is the scalar "$in" doing in the if{ } clause??
- Where are you getting/setting your "$arrayref"?
| [reply] |
|
|
| [reply] [d/l] |
Re: Can this If/Else be condensed into a 1 liner with a trailing If?
by George_Sherston (Vicar) on Oct 02, 2001 at 16:10 UTC
|
I think I must be missing something about the if bit - it doesn't seem to do anything. If that's right, then you could get the same result with
print "$in was not a number!"; input() unless $in =~ /\d/;
which does get it on one line, though not, I agree, with a trailing if :). On the other hand if the line
$in;
is a line you need (perhaps an idiom I don't know - if so, what does it do? - in any event it has a certain classically simplicity about it) - then to get it on one line you could use the conditional operator, although there might be some pros and cons here I don't know about:
$in =~ /\d/ ? $in : print "$in was not a number!";
That doesn't let you call input(), but that's ok if you agree with lesstrat that it might get a bit ropey if you call input() from within input().
On the broader question of how to detect numbers, I find that what I usually want to isolate is everything that isn't not a number, so my favourite idiom is
$in !~ /\D/
But this question is much more complicated than one would think, as these and threads explain.
§ George Sherston | [reply] [d/l] [select] |
|
|
sub foo {
'foo';
}
will return foo even without an explicit return 'foo';
so in a case like the following
print(foo(),"\n");
sub foo {
if(1) {
'foo';
} else {
'bar';
}
}
foo will be printed, since it is the last real value perl saw in the subroutine, everything else was basically blank lines... BUT! one must be careful in this situation because if you ever come back and put code in after the if statement like
print(foo(),"\n");
sub foo {
if(1) {
'foo';
} else {
'bar';
}
print STDERR 'fooed';
}
then you will get 1, the return value of a successful print.
most people use an explicit return unless the value they are returning is the last line of the sub, since it is then much harder to miss.
- Ant
- Some of my best work - Fish Dinner
| [reply] [d/l] [select] |
|
|
Hmm. I thought it might be something like that, but now instead of a nebulous feeling that it must be something to do with returning values I actually know how it works! Very educational - thanks for the explanation. My subroutines will be grateful too.
So (just getting this straight, hoping my thought processes won't be too dull for others) in jerrygarciuh's case, if he replaces the if... else with
print "$in was not a number!"; input() unless $in =~ /\d/;
then the subroutine will return the number of characters chomped from $in, rather than $in itself. So in order to reduce the if... else loop to a single line, one wd have to do something like
sub input {
my $arrayref=shift;
print "\nSo far you've guessed @$arrayref."
if $arrayref;
print "\nWhat is your guess?\n";
chomp <STDIN>;
my $in=<STDIN>;
print "$in wasn't a number!";input() unless $in =~ /\d/;
}
Would that work? Is it nicer? Have I learnt something from this exchange? (The answer to at least one of these questions is "yes".)
§ George Sherston | [reply] [d/l] [select] |
|
|
|
|
#! /usr/local/bin/perl -w
use strict;
$a = 1;
$b = 2;
(1) ? $a = 3 : $b = 4;
print "1) a = $a, b = $b\n";
(1) ? ($a = 3) : ($b = 4);
print "2) a = $a, b = $b\n";
displays:
1) a = 4, b = 2
2) a = 3, b = 2
Which may or may not be what you expect.
Good luck!
{NULE}
PS I'm having issues with Opera again, please forgive me if I screw this post up (again.) Time for a new web-browser *sigh*. | [reply] [d/l] [select] |
Re: Can this If/Else be condensed into a 1 liner with a trailing If?
by Caillte (Friar) on Oct 02, 2001 at 15:30 UTC
|
while($x=<STDIN> and $x !~ /^\s*\d+\s*$/) { print "Enter a number\n" }
$japh->{'Caillte'} = $me; | [reply] [d/l] [select] |