Numeric or character ?

J

John Cecere

Since

if ("aaa" == 0) {
print "true\n";
}

will print true, how does one go about testing a value as an integer. For example, the user enters data:

$a=<STDIN>;

The user might accidentally type in character data, but I need to perform a test to see if what they entered is a number between 0
and 255, and return a bad status for anything else. Doing this:

if ($a < 0 || $a > 255)

won't catch character data.

What's the _simple_ way of doing this ?

Thanks,
John Cecere
 
A

A. Sinan Unur

Since

if ("aaa" == 0) {
print "true\n";
}

will print true, how does one go about testing a value as an integer.
For example, the user enters data:

$a=<STDIN>;

The user might accidentally type in character data,

You seem to be unaware that everything that is stored in $a
at this point is *character* data. If the user enters 110,
$a will contain the string consisting of the characters '1',
'1', and '0', not the integer 110.
need to perform a test to see if what they entered is a number
between 0 and 255, and return a bad status for anything else.
Doing this:

if ($a < 0 || $a > 255)

Of course not, you have a string in $a and you are comparing it
to a number, and therefore it is subject to all the conditions of
number to string conversion in Perl.

BTW, the variables $a and $b are special in Perl
(see perldoc -f sort). You should not use them willy-nilly.
What's the _simple_ way of doing this ?

In general, one checks if input conforms to a certain format by
using an appropriate regex match. In this case, it is a very
simple one:

#!/usr/bin/perl

use strict;
use warnings;

my $input;

$| = 1;

do {
print "Please enter and integer between 0 and 255: ";
$input = <STDIN>;
} until $input =~ /^(\d\d?\d?)$/ and 0 + $1 < 256;

print "You entered: $input\n";

__END__

For more general numeric formats, see

<URL:http://search.cpan.org/~abigail/Regexp-Common-2.120/lib/Regexp/Common/number.pm>

Sinan
 
A

A. Sinan Unur

A. Sinan Unur ([email protected]) wrote on MMMMCCCXL September
MCMXCIII in <URL://
// BTW, the variables $a and $b are special in Perl
// (see perldoc -f sort). You should not use them willy-nilly.

I use $a and $b willy-nilly all the time, and I have never ran into
trouble. While it is possible to create code that might do something
unexpected, it takes a bit of an effort to do so.

True, but I have a knack for unintentionally discovering the complicated
steps to produce unlikely scenarios while doing somthing completely
mundane.

Sinan
 
J

Jürgen Exner

John said:
Since

if ("aaa" == 0) {
print "true\n";
}

will print true, how does one go about testing a value as an integer.
For example, the user enters data:
$a=<STDIN>;

The user might accidentally type in character data,

Well, I hope he does. How could he type anything that is not a character?
but I need to
perform a test to see if what they entered is a number between 0 and
255, and return a bad status for anything else.

First of all I suggest to get your terminology right. The user enters a
sequence of characters. You want to restrict this to digits. And then Perl
can interpret a sequence of digits as a number. While this might seem to be
nitpicking it actually helps immensely to partition your problem in the
right way.

Having said that, is there anything wrong with the answer given in the FAQ?
perldoc -q number:
"How do I determine whether a scalar is a number/whole/integer/float?"
Doing this:
if ($a < 0 || $a > 255)

won't catch character data.

By some definiton of "character" which has nothing to do with the standard
definition of character.
Of course it doesn't because you are comparing the numerical value of a
scalar. If you want to test the characters of string (yes, even digits are
characters) then use a function that uses strings or characters, e.g.
pattern matching or substr or pos or similar.
What's the _simple_ way of doing this ?

Maybe the way as suggested in the FAQ?

jue
 
S

Sven-Thorsten Fahrbach

In general, one checks if input conforms to a certain format by
using an appropriate regex match. In this case, it is a very
simple one:

#!/usr/bin/perl

use strict;
use warnings;

my $input;

$| = 1;

I'm just being interested: is there any specific reason why you make output unbuffered here? I think it's not necessary for this script but maybe something has escaped me...
 
A

Anno Siegel

Sven-Thorsten Fahrbach said:
I'm just being interested: is there any specific reason why you make
output unbuffered here? I think it's not necessary for this script but
maybe something has escaped me...

Autoflushing (which is more to the point than "unbuffered") isn't
exactly needed here, but it's convenient to have. Its main purpose
is to match the flushing behavior of STDOUT and STDERR so that messages
on both appear on the screen when they are printed, not when a buffer
happens to overflow. Otherwise, error messages and normal output may
appear out of sequence, which can be confusing.

I put "$| = 1" in all my scripts (not modules), and only take it out
when the script happens to do mass IO via STDOUT (as in a filter).

Anno
 
S

Sven-Thorsten Fahrbach

I'm just being interested: is there any specific reason why you make
output unbuffered here? I think it's not necessary for this script but
maybe something has escaped me...

Autoflushing (which is more to the point than "unbuffered") isn't
exactly needed here, but it's convenient to have. Its main purpose
is to match the flushing behavior of STDOUT and STDERR so that messages
on both appear on the screen when they are printed, not when a buffer
happens to overflow. Otherwise, error messages and normal output may
appear out of sequence, which can be confusing.

I put "$| = 1" in all my scripts (not modules), and only take it out
when the script happens to do mass IO via STDOUT (as in a filter).[/QUOTE]

Okay, I know what it does, I just wasn't aware that this was kind of a custom among some programmers. When I need unbuffered output I let it go to STDERR usually which is unbuffered (or autoflushed if you prefer) by default.
 
A

Anno Siegel

Sven-Thorsten Fahrbach said:
On 27 Jul 2005 10:00:22 GMT
Sven-Thorsten Fahrbach <[email protected]> wrote in comp.lang.perl.misc:

[...]
Autoflushing (which is more to the point than "unbuffered") isn't
exactly needed here, but it's convenient to have. Its main purpose
is to match the flushing behavior of STDOUT and STDERR so that messages
on both appear on the screen when they are printed, not when a buffer
happens to overflow. Otherwise, error messages and normal output may
appear out of sequence, which can be confusing.

I put "$| = 1" in all my scripts (not modules), and only take it out
when the script happens to do mass IO via STDOUT (as in a filter).

Okay, I know what it does, I just wasn't aware that this was kind of a
custom among some programmers. When I need unbuffered output I let it go
to STDERR usually which is unbuffered (or autoflushed if you prefer) by
default.

It's not just preference. An autoflushed IO channel is still buffered,
the buffer just doesn't fill up so much. A truly unbuffered channel
would be very hard to use.

Otherwise, the purpose of "$| = 1" isn't that we want STDOUT autoflushed,
it's that there already *is* autoflushed output that merges with it,
and the merging is smoother when both are autoflushed.

The problem is often not visible when printing directly to the terminal,
because terminal output is usually line buffered (another form of automatic
flushing). When the output goes to a file or pipe, to "| more" for
instance, the difference becomes apparent. Watch this:

[anno4000@lublin ~/clpm]$ cat script
#!/usr/bin/perl
use strict; use warnings;

$| = shift || 0;

print "one\n";
warn "two\n";
print "three\n";

[anno4000@lublin ~/clpm]$ ./script |& more
two
one
three

4000@lublin ~/clpm]$ ./script 1 |& more
one
two
three

Only in the second (autoflushed) example does the output appear in
the sequence it is produced. That is the problem "$| = 1" avoids.

Anno
 
S

Sven-Thorsten Fahrbach

On 27 Jul 2005 11:56:27 GMT
It's not just preference. An autoflushed IO channel is still buffered,
the buffer just doesn't fill up so much. A truly unbuffered channel
would be very hard to use.

Otherwise, the purpose of "$| = 1" isn't that we want STDOUT autoflushed,
it's that there already *is* autoflushed output that merges with it,
and the merging is smoother when both are autoflushed.

The problem is often not visible when printing directly to the terminal,
because terminal output is usually line buffered (another form of automatic
flushing). When the output goes to a file or pipe, to "| more" for
instance, the difference becomes apparent. Watch this:

[anno4000@lublin ~/clpm]$ cat script
#!/usr/bin/perl
use strict; use warnings;

$| = shift || 0;

print "one\n";
warn "two\n";
print "three\n";

[anno4000@lublin ~/clpm]$ ./script |& more
two
one
three

4000@lublin ~/clpm]$ ./script 1 |& more
one
two
three

Only in the second (autoflushed) example does the output appear in
the sequence it is produced. That is the problem "$| = 1" avoids.

All right, that was enlightening, though I would not consider it a 'problem' exactly. If I come across a situation where non-autoflushed output might not be desireable, I print to STDERR or set $| = 1. I don't come from a profound C background, though, so I might be a little ignorant ;-).
Excerpt from the Camel Book: 'Contrary to popular belief, setting this [$|] variable does not turn off buffering.'
Okey, my bad.

SveTho
 
A

Anno Siegel

Sven-Thorsten Fahrbach said:
On 27 Jul 2005 11:56:27 GMT
(e-mail address removed)-berlin.de (Anno Siegel) wrote:

[Why do some set $| = 1 routinely? Demo how STDOUT and STDERR get out
of sequence if you don't]
All right, that was enlightening, though I would not consider it a
'problem' exactly. If I come across a situation where non-autoflushed
output might not be desireable, I print to STDERR or set $| = 1.

Sure, like everyone. The question was, why do it routinely. When working
on a program you don't want to see, say, the error message it died with
in front of material it has produced before it died.

There are other reasons to use it. If you want to watch a program's
file output through "tail -f ...", it will look jerky unless autoflushed.
Also, if you do an improvised user dialog through STDOUT and STDIN,
users may not see your prompt on some systems unless you autoflush
STDOUT. So it also makes a program more portable. Under normal
circumstances it doesn't hurt much. The exception is mass output
which becomes inefficient. It's the only reason I can think of to
turn it off.

Anno
 
D

David Combs

SNIP

#!/usr/bin/perl

use strict;
use warnings;

my $input;

$| = 1;

do {
print "Please enter and integer between 0 and 255: ";
$input = <STDIN>;
} until $input =~ /^(\d\d?\d?)$/ and 0 + $1 < 256;

print "You entered: $input\n";

__END__
....

Following Damian's new book (Perl Best Practices) (plus this group),
might it be safer to localize $|?

David
 

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. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top