NetBeans in the Classroom: Scanners, Regular Expressions, and Beethoven
Join the DZone community and get the full member experience.
Join For Free
in the courses that i teach, i explain the importance of validation of user input. validation should occur as close to the end user as possible and as soon as possible. before data finds its way to its destination in an object, it should be subject to validation. this should happen immediately after the input is complete and before any subsequent input. in some cases it is even possible to validate input keystroke by keystroke. i tell my students to use every means available.
in a previous article, i wrote about using a simple regular expression to validate character input. the expression ensured that the range of allowable characters was determined by the expression. i have always been in awe of programmers who can write regular expressions. since it is not part of the curriculum that i teach i have avoided learning this craft. i can get away with this because there are so many great web sites that will write the expression for me. a few years ago i found the utility mill and their regex_for_range at this location:
http://utilitymill.com/utility/regex_for_range
this web based utility will accept a minimum and maximum value for a range and then generates the regular expression. the only restriction is that it is a range of positive integers starting at zero. for example, i was looking to validate the range from 0-744. entering this information into the web page’s form gave me:
([0-9]{1,2}|[1-6][0-9]{2}|7[0-3][0-9]|74[0-4])
i won’t bother to explain how this works because one of the options on the form is ‘verbose (see how the pattern is built step by step)’ where the expression is clearly explained. i strongly recommend using this option. it makes me think i could write a regular expression on my own, maybe.
now i can write a scanner input routine that looks like this:
int number = 0; system.out.println("enter a number from 0 to 744: "); if (sc.hasnext("([0-9]|[1-9][0-9]|[1-7][0-4][0-4])")) { number = sc.nextint(); } else { number = -1; }notice that the regular expression is used in hasnext() and not hasnextint(). only the string version of the hasxxx() methods can accept a regular expression. if the pattern of the string matches the expression the it is safe to read it with the nextint() method. if the match fails then a value outside the range such as -1 is assigned to the number.
i implement this using a pattern that is probably quite old and definitely inefficient. the pattern is the primary read, secondary read. i have actually never found a web page or reference to this. i learned it from a cobol teacher in the 80s.
in this pattern you first ask the user for input and immediately validate it. if the validation fails you enter a loop where you are asked again for the input but with a message that indicates that something just went wrong. you stay in this loop until you enter valid input.
/** * primary read, secondary read pattern * * @return */ public int getanumber() { int number; // primary read system.out.println("enter a number from 0 to 744: "); if (sc.hasnext("([0-9]|[1-9][0-9]|[1-7][0-4][0-4])")) { number = sc.nextint(); } else { number = -1; } sc.nextline(); // clear out the input buffer // secondary read while (number == -1) { system.out.println("invalid. enter a number from 0 to 744: "); if (sc.hasnext("([0-9]|[1-9][0-9]|[1-7][0-4][0-4])")) { number = sc.nextint(); } else { number = -1; } sc.nextline(); // clear out the input buffer } return number; }
normally all local variables such as number in this example should be initialized. however the first if statement ensures that number receives a value.
user input terminates when the first whitespace character is encountered. these characters are the space, the tab and the newline. if a use entered “123 210” then 123 would be accepted but 210 would remain in the input buffer so that it will be accepted as the next user input. the sc.nextline() reads anything left in the buffer to guard against this.
the problem with this code is that the majority of the code is repeated. it becomes easy to make a change in one hasnext() and forget to make the change in the other one. the solution is to combine them into one loop. here now is the finished version.
/** * validated input * @return */ public int getanumber2() { int number; do { system.out.println("enter a number from 0 to 744: "); if (sc.hasnext("([0-9]|[1-9][0-9]|[1-7][0-4][0-4])")) { number = sc.nextint(); } else { number = -1; } sc.nextline(); // clear out the keyboard buffer if (number == -1) { system.out.print("your input was invalid. "); } } while (number == -1); return number; }
the beethoven test
the beethoven test is a tongue-in-cheek technique for determining if an input routine is user-proof. it is very simple to carry out. run your program and at every input hum the opening notes of beethoven’s fifth symphony.
while humming pretend to play these notes using as many keys on the keyboard as possible. if you are an iron butterfly fan you can use in-a-gadda-da-vida. after doing this a few times press the enter key.
if your program does not crash but does reject the input then it has passed the test. any other result indicates a failure with your input routine.
Opinions expressed by DZone contributors are their own.
Trending
-
Measuring Service Performance: The Whys and Hows
-
Testing, Monitoring, and Data Observability: What’s the Difference?
-
How To Backup and Restore a PostgreSQL Database
-
RBAC With API Gateway and Open Policy Agent (OPA)
Comments