scanner nextline clase java io java.util.scanner

java - clase - ¿El escáner está saltando nextLine() después de usar next() o nextFoo()?



sc nextline() (14)

¿Por qué no usar un nuevo escáner para cada lectura? Como abajo. Con este enfoque no enfrentarás tu problema.

int i = new Scanner(System.in).nextInt();

Estoy usando los métodos de Scanner nextInt() y nextLine() para leer la entrada.

Se parece a esto:

System.out.println("Enter numerical value"); int option; option = input.nextInt(); // Read numerical value from input System.out.println("Enter 1st string"); String string1 = input.nextLine(); // Read 1st string (this is skipped) System.out.println("Enter 2nd string"); String string2 = input.nextLine(); // Read 2nd string (this appears right after reading numerical value)

El problema es que después de ingresar el valor numérico, la primera input.nextLine() se omite y la segunda input.nextLine() se ejecuta, de modo que mi salida se vea así:

Enter numerical value 3 // This is my input Enter 1st string // The program is supposed to stop here and wait for my input, but is skipped Enter 2nd string // ...and this line is executed and waits for my input

Probé mi aplicación y parece que el problema está en usar input.nextInt() . Si lo elimino, entonces string1 = input.nextLine() y string2 = input.nextLine() se ejecutan como quiero que sean.


Cosas que necesitas saber:

  • el texto que representa pocas líneas también contiene caracteres no imprimibles entre líneas (los llamamos separadores de línea) como

    • retorno de carro (CR - en literales de cadena representados como "/r" )
    • avance de línea (LF - en literales de cadena representados como "/n" )
  • cuando está leyendo datos desde la consola, le permite al usuario escribir su respuesta y cuando termina, necesita confirmar de alguna manera ese hecho. Para hacerlo, el usuario debe presionar la tecla "enter" / "return" en el teclado.

    Lo que es importante es que esta clave además de garantizar la colocación de los datos del usuario en la entrada estándar (representada por System.in que lee Scanner ) también envía separadores de línea dependientes del sistema operativo (como para Windows /r/n ) después de esta.

    Entonces, cuando le pide al usuario un valor como la age y el usuario escribe 42 y presiona Intro, la entrada estándar contendrá "42/r/n" .

Problema

Scanner#nextInt (y otros métodos Scanner#next Type ) no permiten que Scanner consuma estos separadores de línea. Los leerá desde System.in (¿de qué otra manera sabría Scanner que no hay más dígitos del usuario que representen el valor de la age que los espacios en blanco?) Lo que los eliminará de la entrada estándar, pero también almacenará esos separadores de línea internamente . Lo que debemos recordar es que todos los métodos del escáner siempre se escanean a partir del texto en caché.

Ahora Scanner#nextLine() simplemente recopila y devuelve todos los caracteres hasta que encuentra los separadores de línea (o el final de la secuencia). Pero como los separadores de línea después de leer el número de la consola se encuentran inmediatamente en la memoria caché del Escáner, devuelve una Cadena vacía, lo que significa que el Escáner no pudo encontrar ningún carácter antes de esos separadores de línea (o final del flujo).
BTW nextLine también consume esos separadores de línea.

Solución

Entonces, cuando quiera pedir un número y luego una línea completa, evitando esa cadena vacía como resultado de nextLine , ya sea

  • consumir separador de línea dejado por nextInt desde la caché de escáneres por
    • llamando a nextLine ,
    • o llamando a skip("//R") para permitir que Scanner omita la parte que coincide con /R que representa el separador de línea (más información sobre /R : https://.com/a/31060125 )
  • no use nextInt (ni next , ni ningún método nextTYPE ) en absoluto. En lugar de eso, lea los datos completos línea por línea usando nextLine y nextLine números de cada línea (suponiendo que una línea contenga solo un número) al tipo correcto como int través de Integer.parseInt .

BTW : Scanner#next Type métodos de Scanner#next Type pueden omitir los delimitadores (de forma predeterminada, todos los espacios en blanco, como las pestañas, los separadores de línea), incluidos los almacenados en la memoria caché por el escáner, hasta que encuentren el siguiente valor no delimitador (token). Gracias a eso por la entrada como el código "42/r/n/r/n321/r/n/r/n/r/nfoobar"

int num1 = sc.nextInt(); int num2 = sc.nextInt(); String name = sc.next();

será capaz de asignar correctamente num1=42 num2=321 name=foobar .


El problema está en el método input.nextInt () : solo lee el valor int. Entonces, cuando continúe leyendo con input.nextLine () recibirá la tecla "/ n" Enter. Así que para omitir esto tienes que agregar el input.nextLine () . Espero que esto debería quedar claro ahora.

Inténtalo así:

System.out.print("Insert a number: "); int number = input.nextInt(); input.nextLine(); // This line you have to add (It consumes the /n character) System.out.print("Text1: "); String text1 = input.nextLine(); System.out.print("Text2: "); String text2 = input.nextLine();


En lugar de input.nextLine() use input.next() , eso debería resolver el problema.

Código modificado:

public static Scanner input = new Scanner(System.in); public static void main(String[] args) { System.out.print("Insert a number: "); int number = input.nextInt(); System.out.print("Text1: "); String text1 = input.next(); System.out.print("Text2: "); String text2 = input.next(); }


Esto se debe a que cuando ingresa un número, luego presione Entrar , input.nextInt() consume solo el número, no el "fin de línea". Cuando se ejecuta input.nextLine() , consume el "fin de línea" que aún se encuentra en el búfer desde la primera entrada.

En su lugar, use input.nextLine() inmediatamente después de input.nextInt()


Esto se debe a que el método Scanner.nextInt no lee el carácter de nueva línea en su entrada creada al presionar "Enter", por lo que la llamada a Scanner.nextLine regresa después de leer esa nueva línea .

Encontrará un comportamiento similar cuando use Scanner.nextLine después de Scanner.next() o cualquier método nextLine (excepto nextLine sí).

Solución:

  • Scanner.nextLine una llamada a Scanner.nextLine después de cada Scanner.nextInt o Scanner.nextFoo para consumir el resto de esa línea, incluida la nueva línea

    int option = input.nextInt(); input.nextLine(); // Consume newline left-over String str1 = input.nextLine();

  • O, mejor aún, lea la entrada a través de Scanner.nextLine y convierta su entrada al formato adecuado que necesita. Por ejemplo, puede convertir a un entero usando el método Integer.parseInt(String) .

    int option = 0; try { option = Integer.parseInt(input.nextLine()); } catch (NumberFormatException e) { e.printStackTrace(); } String str1 = input.nextLine();


Lo hace porque input.nextInt(); No captura la nueva línea. puede hacer como las otras propuestas al agregar un input.nextLine(); debajo.
Alternativamente, puede hacerlo con el estilo C # y analizar una nextLine a un entero como:

int number = Integer.parseInt(input.nextLine());

Hacer esto funciona igual de bien y le ahorra una línea de código.


Para evitar el problema, use nextLine(); inmediatamente después de nextInt(); ya que ayuda en la eliminación de la memoria intermedia. Cuando presionas ENTER el nextInt(); no captura la nueva línea y, por lo tanto, omite el código del Scanner más adelante.

Scanner scanner = new Scanner(System.in); int option = scanner.nextInt(); scanner.nextLine(); //clearing the buffer


Parece que hay muchas preguntas sobre este problema con java.util.Scanner . Creo que una solución más legible / idiomática sería llamar a scanner.skip("[/r/n]+") para eliminar cualquier carácter de nueva línea después de llamar a nextInt() .

EDITAR: como @PatrickParker señala a continuación, esto causará un bucle infinito si el usuario ingresa cualquier espacio en blanco después del número. Vea su respuesta para un mejor patrón para usar con skip: https://.com/a/42471816/143585


Si desea escanear la entrada rápidamente sin confundirse con el método nextLine () de la clase de escáner, use el escáner de entrada personalizado para ello.

Código:

class ScanReader { /** * @author Nikunj Khokhar */ private byte[] buf = new byte[4 * 1024]; private int index; private BufferedInputStream in; private int total; public ScanReader(InputStream inputStream) { in = new BufferedInputStream(inputStream); } private int scan() throws IOException { if (index >= total) { index = 0; total = in.read(buf); if (total <= 0) return -1; } return buf[index++]; } public char scanChar(){ int c=scan(); while (isWhiteSpace(c))c=scan(); return (char)c; } public int scanInt() throws IOException { int integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == ''-'') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= ''0'' && n <= ''9'') { integer *= 10; integer += n - ''0''; n = scan(); } } return neg * integer; } public String scanString() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); StringBuilder res = new StringBuilder(); do { res.appendCodePoint(c); c = scan(); } while (!isWhiteSpace(c)); return res.toString(); } private boolean isWhiteSpace(int n) { if (n == '' '' || n == ''/n'' || n == ''/r'' || n == ''/t'' || n == -1) return true; else return false; } public long scanLong() throws IOException { long integer = 0; int n = scan(); while (isWhiteSpace(n)) n = scan(); int neg = 1; if (n == ''-'') { neg = -1; n = scan(); } while (!isWhiteSpace(n)) { if (n >= ''0'' && n <= ''9'') { integer *= 10; integer += n - ''0''; n = scan(); } } return neg * integer; } public void scanLong(long[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanLong(); } public void scanInt(int[] A) throws IOException { for (int i = 0; i < A.length; i++) A[i] = scanInt(); } public double scanDouble() throws IOException { int c = scan(); while (isWhiteSpace(c)) c = scan(); int sgn = 1; if (c == ''-'') { sgn = -1; c = scan(); } double res = 0; while (!isWhiteSpace(c) && c != ''.'') { if (c == ''e'' || c == ''E'') { return res * Math.pow(10, scanInt()); } res *= 10; res += c - ''0''; c = scan(); } if (c == ''.'') { c = scan(); double m = 1; while (!isWhiteSpace(c)) { if (c == ''e'' || c == ''E'') { return res * Math.pow(10, scanInt()); } m /= 10; res += (c - ''0'') * m; c = scan(); } } return res * sgn; } }

Ventajas:

  • Escanea la entrada más rápido que BufferReader
  • Reduce la complejidad del tiempo
  • Flushes Buffer para cada entrada siguiente

Métodos:

  • scanChar () - escanear un solo carácter
  • scanInt () - escanea valor entero
  • scanLong () - scan Long value
  • scanString () - escanea el valor de la cadena
  • scanDouble () - escanear doble valor
  • scanInt (int [] array): analiza la matriz completa (entero)
  • scanLong (long [] array): escanea el array completo (Long)

Uso:

  1. Copia el código dado debajo de tu código java.
  2. Inicializar objeto para una clase dada

ScanReader sc = new ScanReader(System.in); 3. Importar Clases necesarias:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Tire la IOException de su método principal para manejar la Excepción 5. Use los Métodos provistos. 6. disfrutar

Ejemplo:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; class Main{ public static void main(String... as) throws IOException{ ScanReader sc = new ScanReader(System.in); int a=sc.scanInt(); System.out.println(a); } } class ScanReader....


Si desea leer tanto cadenas como instrucciones, una solución es utilizar dos escáneres:

Scanner stringScanner = new Scanner(System.in); Scanner intScanner = new Scanner(System.in); intScanner.nextInt(); String s = stringScanner.nextLine(); // unaffected by previous nextInt() System.out.println(s); intScanner.close(); stringScanner.close();


Supongo que llego bastante tarde a la fiesta ..

Como se indicó anteriormente, llamar a input.nextLine() después de obtener su valor int resolverá su problema. La razón por la que su código no funcionó fue porque no había nada más que almacenar desde su entrada (donde ingresó el int) en string1 . Acabo de aclarar un poco más todo el tema.

Considere nextLine () como la opción impar entre los métodos nextFoo () en la clase Scanner. Tomemos un ejemplo rápido. Digamos que tenemos dos líneas de código como las siguientes:

int firstNumber = input.nextInt(); int secondNumber = input.nextInt();

Si ingresamos el valor abajo (como una sola línea de entrada)

54 234

El valor de nuestra variable firstNumber y secondNumber convierte en 54 y 234 respectivamente. La razón por la que esto funciona de esta manera es porque una nueva línea de alimentación ( es decir, / n ) NO SE genera automáticamente cuando el método nextInt () toma los valores. Simplemente toma el "siguiente int" y sigue adelante. Esto es lo mismo para el resto de los métodos nextFoo () excepto nextLine ().

nextLine () genera un nuevo salto de línea inmediatamente después de tomar un valor; esto es lo que @RohitJain quiere decir al decir que la nueva línea se "consume".

Por último, el método next () simplemente toma la cadena más cercana sin generar una nueva línea; esto hace que este sea el método preferencial para tomar cadenas separadas dentro de la misma línea.

Espero que esto ayude .. Feliz codificación!


sc.nextLine() es mejor en comparación con el análisis de la entrada. Porque el rendimiento sabio será bueno.


public static void main(String[] args) { Scanner scan = new Scanner(System.in); int i = scan.nextInt(); scan.nextLine(); double d = scan.nextDouble(); scan.nextLine(); String s = scan.nextLine(); System.out.println("String: " + s); System.out.println("Double: " + d); System.out.println("Int: " + i); }