Validando la entrada usando java.util.Scanner [duplicado]
Estoy tomando información del usuario al System.in
usar un archivo java.util.Scanner
. Necesito validar la entrada para cosas como:
- Debe ser un número no negativo.
- Debe ser una letra alfabética.
- ... etc
¿Cuál es la mejor manera de hacer esto?
Resumen de Scanner.hasNextXXX
métodos
java.util.Scanner
tiene muchos hasNextXXX
métodos que se pueden utilizar para validar la entrada. A continuación se ofrece una breve descripción general de todos ellos:
hasNext()
- ¿Tiene alguna ficha?hasNextLine()
- ¿Tiene otra línea de entrada?- Para primitivas de Java
hasNextInt()
- ¿Tiene un token que pueda analizarse en unint
?- También están disponibles
hasNextDouble()
,hasNextFloat()
,hasNextByte()
,hasNextShort()
,hasNextLong()
, yhasNextBoolean()
- Como beneficio adicional, también hay
hasNextBigInteger()
yhasNextBigDecimal()
- Los tipos integrales también tienen sobrecargas para especificar la base (por ejemplo, hexadecimal)
- Basado en expresiones regulares
hasNext(String pattern)
hasNext(Pattern pattern)
es laPattern.compile
sobrecarga
Scanner
es capaz de hacer más, gracias al hecho de que está basado en expresiones regulares. Una característica importante es useDelimiter(String pattern)
que le permite definir qué patrón separa sus tokens. find
También existen skip
métodos que ignoran los delimitadores.
La siguiente discusión mantendrá la expresión regular lo más simple posible, por lo que el foco permanece en Scanner
.
Ejemplo 1: validar entradas positivas
A continuación se muestra un ejemplo sencillo de uso hasNextInt()
para validar resultados positivos int
de la entrada.
Scanner sc = new Scanner(System.in);
int number;
do {
System.out.println("Please enter a positive number!");
while (!sc.hasNextInt()) {
System.out.println("That's not a number!");
sc.next(); // this is important!
}
number = sc.nextInt();
} while (number <= 0);
System.out.println("Thank you! Got " + number);
Aquí hay una sesión de ejemplo:
¡Por favor ingrese un número positivo!
cinco ¡
Ese no es un número!
-3
¡Ingrese un número positivo!
5
¡Gracias! Tengo 5
Tenga en cuenta que es mucho más fácil Scanner.hasNextInt()
de usar en comparación con el combo try/catch
Integer.parseInt
/ más detallado NumberFormatException
. Por contrato, a garantiza Scanner
que si lo hace hasNextInt()
, se nextInt()
lo entregará pacíficamente int
y no arrojará ningún NumberFormatException
// .InputMismatchException
NoSuchElementException
Preguntas relacionadas
- Cómo usar Scanner para aceptar solo int válido como entrada
- ¿Cómo evito que un escáner genere excepciones cuando se ingresa el tipo incorrecto? (Java)
Ejemplo 2: múltiples hasNextXXX
en el mismo token
Tenga en cuenta que el fragmento anterior contiene una sc.next()
declaración para avanzar Scanner
hasta que hasNextInt()
. ¡Es importante darse cuenta de que ninguno de los hasNextXXX
métodos avanza más Scanner
allá de cualquier entrada! Descubrirá que si omite esta línea del fragmento, entrará en un bucle infinito con una entrada no válida.
Esto tiene dos consecuencias:
- Si necesita omitir la entrada "basura" que no pasa la
hasNextXXX
prueba, entonces debe avanzar deScanner
una forma u otra (por ejemplonext()
,nextLine()
,skip
, etc.). - Si una prueba falla, aún
hasNextXXX
puedes probar si es así .hasNextYYY
A continuación se muestra un ejemplo de cómo realizar varias hasNextXXX
pruebas.
Scanner sc = new Scanner(System.in);
while (!sc.hasNext("exit")) {
System.out.println(
sc.hasNextInt() ? "(int) " + sc.nextInt() :
sc.hasNextLong() ? "(long) " + sc.nextLong() :
sc.hasNextDouble() ? "(double) " + sc.nextDouble() :
sc.hasNextBoolean() ? "(boolean) " + sc.nextBoolean() :
"(String) " + sc.next()
);
}
Aquí hay una sesión de ejemplo:
5
(int) 5
false
(boolean) false
bla
(String) bla
1.1
(doble) 1.1
100000000000
(largo) 100000000000
salir
Tenga en cuenta que el orden de las pruebas es importante. Si es a Scanner
hasNextInt()
, entonces también es hasNextLong()
, pero no necesariamente es true
al revés. La mayoría de las veces querrás realizar la prueba más específica antes de la prueba más general.
Ejemplo 3: Validación de vocales
Scanner
Tiene muchas funciones avanzadas compatibles con expresiones regulares. Aquí hay un ejemplo de cómo usarlo para validar vocales.
Scanner sc = new Scanner(System.in);
System.out.println("Please enter a vowel, lowercase!");
while (!sc.hasNext("[aeiou]")) {
System.out.println("That's not a vowel!");
sc.next();
}
String vowel = sc.next();
System.out.println("Thank you! Got " + vowel);
Aquí hay una sesión de ejemplo:
¡Por favor ingrese una vocal, minúscula!
5
¡Eso no es una vocal!
z ¡
Eso no es una vocal!
¡Gracias
! tengo e
En expresiones regulares, como literal de cadena Java, el patrón "[aeiou]"
es lo que se llama una "clase de carácter"; coincide con cualquiera de las letras a
, e
, i
, o
, u
. Tenga en cuenta que es trivial hacer que la prueba anterior no distinga entre mayúsculas y minúsculas: simplemente proporcione dicho patrón de expresiones regulares al archivo Scanner
.
Enlaces API
hasNext(String pattern)
- Devuelvetrue
si el siguiente token coincide con el patrón construido a partir de la cadena especificada.java.util.regex.Pattern
Preguntas relacionadas
- Leer un solo carácter en Java
Referencias
- Tutoriales de Java/Clases esenciales/Expresiones regulares
- regular-expressions.info/Clases de personajes
Ejemplo 4: usar dos Scanner
a la vez
A veces es necesario escanear línea por línea, con varios tokens en una línea. La forma más sencilla de lograr esto es usar two Scanner
, donde el segundo Scanner
toma nextLine()
del primero Scanner
como entrada. He aquí un ejemplo:
Scanner sc = new Scanner(System.in);
System.out.println("Give me a bunch of numbers in a line (or 'exit')");
while (!sc.hasNext("exit")) {
Scanner lineSc = new Scanner(sc.nextLine());
int sum = 0;
while (lineSc.hasNextInt()) {
sum += lineSc.nextInt();
}
System.out.println("Sum is " + sum);
}
Aquí hay una sesión de ejemplo:
Dame un montón de números en una línea (o 'salida')
3 4 5
La suma es 12
10 100 un millón de dólares
La suma es 110
espera ¿qué?
La suma es 0
salida
Además de Scanner(String)
constructor, también hay, Scanner(java.io.File)
entre otros.
Resumen
Scanner
proporciona un rico conjunto de características, comohasNextXXX
métodos de validación.- El uso adecuado de
hasNextXXX/nextXXX
en combinación significa que aScanner
NUNCA arrojará unInputMismatchException
/NoSuchElementException
. - Recuerde siempre que
hasNextXXX
no adelantaScanner
ninguna entrada al pasado. - No dudes en crear varios
Scanner
si es necesario. Dos simplesScanner
son a menudo mejores que uno demasiado complejoScanner
. - Finalmente, incluso si no tiene planes de utilizar las funciones avanzadas de expresiones regulares, tenga en cuenta qué métodos están basados en expresiones regulares y cuáles no. Cualquier
Scanner
método que acepte unString pattern
argumento se basa en expresiones regulares.- Consejo : una manera fácil de convertir cualquier patrón
String
en un patrón literal esPattern.quote
hacerlo.
- Consejo : una manera fácil de convertir cualquier patrón
Aquí tienes una forma minimalista de hacerlo.
System.out.print("Please enter an integer: ");
while(!scan.hasNextInt()) scan.next();
int demoInt = scan.nextInt();
Para comprobar cadenas en busca de letras, puede utilizar expresiones regulares, por ejemplo:
someString.matches("[A-F]");
Para verificar los números y evitar que el programa falle, tengo una clase bastante simple que puedes encontrar a continuación donde puedes definir el rango de valores que deseas. Aquí
public int readInt(String prompt, int min, int max)
{
Scanner scan = new Scanner(System.in);
int number = 0;
//Run once and loop until the input is within the specified range.
do
{
//Print users message.
System.out.printf("\n%s > ", prompt);
//Prevent string input crashing the program.
while (!scan.hasNextInt())
{
System.out.printf("Input doesn't match specifications. Try again.");
System.out.printf("\n%s > ", prompt);
scan.next();
}
//Set the number.
number = scan.nextInt();
//If the number is outside range print an error message.
if (number < min || number > max)
System.out.printf("Input doesn't match specifications. Try again.");
} while (number < min || number > max);
return number;
}
Una idea:
try {
int i = Integer.parseInt(myString);
if (i < 0) {
// Error, negative input
}
} catch (NumberFormatException e) {
// Error, not a number.
}
También existe, en la biblioteca commons-lang , la clase CharUtils que proporciona los métodos isAsciiNumeric()
para verificar que un carácter es un número y isAsciiAlpha()
para verificar que el carácter es una letra...