Validando la entrada usando java.util.Scanner [duplicado]

Resuelto bhavna raghuvanshi asked hace 14 años • 0 respuestas

Estoy tomando información del usuario al System.inusar 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?

bhavna raghuvanshi avatar Jun 17 '10 13:06 bhavna raghuvanshi
Aceptado

Resumen de Scanner.hasNextXXXmétodos

java.util.Scannertiene muchos hasNextXXXmé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 un int?
    • 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 la Pattern.compilesobrecarga

Scanneres 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. findTambién existen skipmé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 intde 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 inty no arrojará ningún NumberFormatException// .InputMismatchExceptionNoSuchElementException

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 hasNextXXXen el mismo token

Tenga en cuenta que el fragmento anterior contiene una sc.next()declaración para avanzar Scannerhasta 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 hasNextXXXprueba, entonces debe avanzar de Scanneruna forma u otra (por ejemplo next(), nextLine(), skip, etc.).
  • Si una prueba falla, aúnhasNextXXX puedes probar si es así .hasNextYYY

A continuación se muestra un ejemplo de cómo realizar varias hasNextXXXpruebas.

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 trueal 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

ScannerTiene 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)- Devuelve truesi 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 Scannera 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 Scannertoma nextLine()del primero Scannercomo 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

  • Scannerproporciona un rico conjunto de características, como hasNextXXXmétodos de validación.
  • El uso adecuado de hasNextXXX/nextXXXen combinación significa que a ScannerNUNCA arrojará un InputMismatchException/ NoSuchElementException.
  • Recuerde siempre que hasNextXXXno adelanta Scannerninguna entrada al pasado.
  • No dudes en crear varios Scannersi es necesario. Dos simples Scannerson a menudo mejores que uno demasiado complejo Scanner.
  • 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 Scannermétodo que acepte un String patternargumento se basa en expresiones regulares.
    • Consejo : una manera fácil de convertir cualquier patrón Stringen un patrón literal es Pattern.quotehacerlo.
polygenelubricants avatar Jun 17 '2010 06:06 polygenelubricants

Aquí tienes una forma minimalista de hacerlo.

System.out.print("Please enter an integer: ");
while(!scan.hasNextInt()) scan.next();
int demoInt = scan.nextInt();
dsharhon avatar May 23 '2014 23:05 dsharhon

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;
}
Duane avatar Dec 02 '2012 13:12 Duane

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...

Romain Linsolas avatar Jun 17 '2010 06:06 Romain Linsolas