http://qs321.pair.com?node_id=336251

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

i wish to grab user entry as STDIN but accept it only if its a 5-digit number. whats the easiest way to do this? thanks!

Replies are listed 'Best First'.
Re: compare stdin for a number
by halley (Prior) on Mar 12, 2004 at 20:20 UTC
    I get downvoted whenever I mention it, but this sounds a lot like homework. So... What have you tried, where did you get stuck, what's the results you got? And if it's not homework, it seems like this is in all the Chapter Ones of any Perl book you could find.

    --
    [ e d @ h a l l e y . c c ]

    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: compare stdin for a number
by NovMonk (Chaplain) on Mar 12, 2004 at 20:41 UTC
    Since I have nothing better to do this afternoon, and I'm just learning, too, I checked my Perl book and came up with this-- does it work? If not, why not?

    #!/usr/bin/perl use strict; Print “enter a 4 digit number:\n”; Test: { my $number = <STDIN>; chomp $number; If $number !=~ /[0-9][0-9][0-9][0-9]/{ Print “try again – 4 digits\n”; Redo TEST; } }

    (I had to look in a couple of chapters of Perl by Example to get this. At least I'm using strict now, though.)

    NovMonk

      Hope you don't mind me making a few comments and I hope you find them helpful.
      #!/usr/bin/perl use strict;
      This is a good start ;) you might want to add use warnings; as well
      Print “enter a 4 digit number:\n”;
      This looks like it has been though word :(
      Word uses odd quoting that changes the quote (") charecter and will capitalise first letters.
      print "enter a 4 digit number:\n";
      Next bit looks ok but personally I would use a while (1) last loop.
      Test: { my $number = <STDIN>; chomp $number;
      Next line has been nobbled by word again but there are also a couple of other issues.
      If $number !=~ /[0-9][0-9][0-9][0-9]/{
      !=~ should be !~ there was a thread the other day covering exactly what !=~ does but don't go there it is bizzare.
      /[0-9][0-9][0-9][0-9]/ matches four digits true enough but it will match anything that contains 4 succesive digits (ie 'ABC12CD E3456FGH') and the original post asked for exactly 5 digits (ignoring the 4 - 5 issue ;)) you need to lock the pattern to the start (^) and end ($) of the string. /^[0-9][0-9][0-9][0-9]$/ would do this.
      if $number !~ /^[0-9][0-9][0-9][0-9]$/ {
      Please use a text editor rather than word which alters what you write.
      Print “try again – 4 digits\n”;
      De-worded this is fine.
      print "try again – 4 digits\n";
      There is a problem with the following line but againg it is related to case sensitivity. The label you loop back to has to match including case. Other wise you get
      Label not found for "redo TEST" at - line 9, <STDIN> line 1.
      Redo TEST;
      Should read :-
      redo Test;
      No errors here.
      } }
      So reassembled :-
      #!/usr/bin/perl use strict; print "enter a 4 digit number:\n"; Test: { my $number = <STDIN>; chomp $number; if ($number !~ /^[0-9][0-9][0-9][0-9]$/) { print "try again – 4 digits\n"; redo Test; } }
      This works and does the job. A very good start. Just please don't use word ;)

      Hope it helps
      UnderMine

      If $number !=~ /[0-9][0-9][0-9][0-9]/{

      If you want a negation you sould use !~ as operator instead of =~ or unless instead of if as condition. The regex matches 4 digits anywhere in $number. Correct use of possible regexe's is explained above.

Re: compare stdin for a number
by Happy-the-monk (Canon) on Mar 12, 2004 at 20:30 UTC

    hmm, then, maybe anoxer you show us how you would proceed, ask questions when you got stuck or where you believe there should be an easier way to do it. We will help you along.

    Sören

Re: compare stdin for a number
by kesterkester (Hermit) on Mar 12, 2004 at 20:34 UTC
    Something like this'll do (you'll probably want to wrap this in a loop to allow the user more than one try to get it right)
    use warnings; use strict; chomp ( $_ = <> ); print "good input\n" if /^\d{5}$/;

      I know that the first time I was learning about regular expressions, "do ___" was much less helpful to me if it didn't include an explanation of why it should be done. I am including one here for completeness.

      The following code

      print "good input\n" if /^\d{5}$/;

      Should Could be rewritten:

      print "good input\n" if /^\d{5,5}$/;

      This is because {}s can contain 2 numbers seperated by a comma. The number on the left is the minimum number of the charachters (or things). The number on the right is the maximum number of charachters (or things). The charachter or thing is whatever is to the left of the {}s. So, \d{5,5} says 5 digits and only 5 digits, whereas \d{5} says at least 5 digits -- but possibly more. (Note that \d means a charachter that represents a number -- i.e. a digit)

      Of course, the reason the original regular expression will still work is the ^ and $ charachter mean "beginning of a line" and "end of a line", respectively. So my regular expression says "at least 5 digits but not more then 5 digits which start on the beginning of a line and end at the end of a line" while the original regular expression says "At least 5 digits between the beginning and end of a line -- and possibly more".

      Of course, the thing we have to pay attention to here is that mine would fail if we tried to match the string "Foo\n12345\nBar" This is because it fits all the constraints of the regular expression. However, because of the angle brackets <> -- which reads in a single line at a time, you know you can only have one line.

      Update: Thanks for pointing out my mistake Tom


      Want to support the EFF and FSF by buying cool stuff? Click here.
        /\d{5}/ means exactly 5(same as /\d{5,5}/).
        /\d{5,}/ means 5 or more.

        - Tom

Re: compare stdin for a number
by tachyon (Chancellor) on Mar 12, 2004 at 22:05 UTC

    Command line switches are handy for some tasks, like -l and -n, which let you write the whole thing in one rather short line:

    C:\>perl -lne "print m/^\d{5}$/ ? ' OK' : ' Fail'" 5 Fail 12345 OK 123 Fail Hello Fail 3.141 Fail ^Z

    cheers

    tachyon