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"
)
- retorno de carro (CR - en literales de cadena representados como
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 leeScanner
) 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 )
- llamando a
- no use
nextInt
(ninext
, ni ningún métodonextTYPE
) en absoluto. En lugar de eso, lea los datos completos línea por línea usandonextLine
ynextLine
números de cada línea (suponiendo que una línea contenga solo un número) al tipo correcto comoint
través deInteger.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 aScanner.nextLine
después de cadaScanner.nextInt
oScanner.nextFoo
para consumir el resto de esa línea, incluida la nueva líneaint 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étodoInteger.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:
- Copia el código dado debajo de tu código java.
- 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);
}