Le scanner ignore nextLine () après avoir utilisé next () ou nextFoo ()?
J'utilise les Scanner
méthodes nextInt()
et nextLine()
pour lire les entrées.
Cela ressemble à ceci:
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)
Le problème est qu'après avoir entré la valeur numérique, la première input.nextLine()
est ignorée et la seconde input.nextLine()
est exécutée, de sorte que ma sortie ressemble à ceci:
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
J'ai testé mon application et il semble que le problème réside dans l'utilisation input.nextInt()
. Si je le supprime, les deux string1 = input.nextLine()
et string2 = input.nextLine()
sont exécutés comme je le souhaite.
Réponses
C'est parce que la Scanner.nextIntméthode ne lit pas le caractère de nouvelle ligne dans votre entrée créée en appuyant sur "Entrée", et donc l'appel à Scanner.nextLineretourne après avoir lu cette nouvelle ligne .
Vous rencontrerez le même comportement lorsque vous utiliserez Scanner.nextLine
after Scanner.next()ou n'importe quelle Scanner.nextFoo
méthode (sauf nextLine
elle-même).
Solution de contournement:
Soit mettre un
Scanner.nextLine
appel après chacun,Scanner.nextInt
soitScanner.nextFoo
consommer le reste de cette ligne, y compris la nouvelle ligneint option = input.nextInt(); input.nextLine(); // Consume newline left-over String str1 = input.nextLine();
Ou, mieux encore, lisez l'entrée
Scanner.nextLine
et convertissez votre entrée au format approprié dont vous avez besoin. Par exemple, vous pouvez convertir en un entier en utilisant Integer.parseInt(String)method.int option = 0; try { option = Integer.parseInt(input.nextLine()); } catch (NumberFormatException e) { e.printStackTrace(); } String str1 = input.nextLine();
Le problème vient de la méthode input.nextInt () - elle ne lit que la valeur int. Ainsi, lorsque vous continuez à lire avec input.nextLine (), vous recevez la touche Entrée "\ n". Donc, pour sauter cela, vous devez ajouter le input.nextLine () . J'espère que cela devrait être clair maintenant.
Essayez-le comme ça:
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();
C'est parce que lorsque vous entrez un nombre puis appuyez sur Enter, input.nextInt()
ne consomme que le nombre, pas la «fin de ligne». Lorsqu'il input.nextLine()
s'exécute, il consomme la "fin de ligne" toujours dans le tampon à partir de la première entrée.
Au lieu de cela, utilisez input.nextLine()
immédiatement aprèsinput.nextInt()
Il semble y avoir de nombreuses questions sur ce problème avec java.util.Scanner
. Je pense qu'une solution plus lisible / idiomatique serait d'appeler scanner.skip("[\r\n]+")
pour supprimer tous les caractères de nouvelle ligne après l'appel nextInt()
.
EDIT: comme @PatrickParker noté ci-dessous, cela provoquera une boucle infinie si l'utilisateur saisit un espace après le nombre. Voir leur réponse pour un meilleur modèle à utiliser avec skip:https://stackoverflow.com/a/42471816/143585
Il fait cela parce input.nextInt();
qu'il ne capture pas la nouvelle ligne. vous pourriez faire comme les autres proposés en ajoutant un input.nextLine();
dessous.
Vous pouvez également le faire en style C # et analyser une nextLine en un entier comme ceci:
int number = Integer.parseInt(input.nextLine());
Cela fonctionne tout aussi bien et cela vous permet d'économiser une ligne de code.
TL; DR À utiliser scanner.skip("\\R")
avant chaque scanner.newLine()
appel, qui est exécuté après:
scanner.next()
scanner.next*TYPE*()
méthode, commescanner.nextInt()
.
Ce que vous devez savoir:
le texte qui représente quelques lignes contient également des caractères non imprimables entre les lignes (nous les appelons des séparateurs de ligne) comme
retour chariot (CR - dans les littéraux de chaîne représentés par
"\r"
)saut de ligne (LF - dans les littéraux de chaîne représentés par
"\n"
)lorsque vous lisez des données à partir de la console, cela permet à l'utilisateur de taper sa réponse et quand il a terminé, il doit en quelque sorte confirmer ce fait. Pour ce faire, l'utilisateur doit appuyer sur la touche «Entrée» / «Retour» du clavier.
Ce qui est important, c'est que cette touche, en plus d'assurer le placement des données utilisateur sur l'entrée standard (représentée par System.in
laquelle est lue par Scanner
), envoie également des séparateurs de ligne dépendants du système d'exploitation (comme pour Windows \r\n
) après elle.
Ainsi, lorsque vous demandez à l'utilisateur une valeur comme age
, et que l'utilisateur tape 42 et appuie sur Entrée, l'entrée standard contiendra "42\r\n"
.
Problème
Scanner#nextInt
(et d' autres méthodes) ne permet pas scanner de consommer ces séparateurs de ligne. Il les lira à partir de (comment le Scanner saurait-il qu'il n'y a plus de chiffres de l'utilisateur qui représentent la valeur que les espaces faisant face?) Ce qui les supprimera de l'entrée standard, mais il mettra également en cache ces séparateurs de ligne en interne . Ce que nous devons nous rappeler, c'est que toutes les méthodes du scanner analysent toujours à partir du texte mis en cache.Scanner#nextType
System.in
age
Maintenant, Scanner#nextLine()
il collecte et renvoie simplement tous les caractères jusqu'à ce qu'il trouve des séparateurs de ligne (ou fin de flux). Mais comme les séparateurs de ligne après la lecture du nombre depuis la console se trouvent immédiatement dans le cache de Scanner, il renvoie une chaîne vide, ce qui signifie que Scanner n'a pas pu trouver de caractère avant ces séparateurs de ligne (ou fin de flux).
BTW consommenextLine
également ces séparateurs de ligne.
Solution
Ainsi, lorsque vous souhaitez demander un nombre, puis une ligne entière tout en évitant cette chaîne vide nextLine
, soit
- consommer le séparateur de ligne laissé par le
nextInt
cache des scanners par - appeler
nextLine
, - ou une manière plus lisible de l' OMI serait d'appeler
skip("\\R")
ouskip("\r\n|\r|\n")
de laisser le scanner ignorer la partie correspondant au séparateur de ligne (plus d'informations sur\R
:https://stackoverflow.com/a/31060125) - ne pas utiliser
nextInt
(ninext
, ni aucunenextTYPE
méthode) du tout. Au lieu de cela, lisez des données entières ligne par ligne en utilisantnextLine
et analysez les nombres de chaque ligne (en supposant qu'une ligne ne contient qu'un seul nombre) dans un type approprié commeint
viaInteger.parseInt
.
BTW : les méthodes peuvent ignorer les délimiteurs (par défaut tous les espaces comme les tabulations, les séparateurs de ligne), y compris ceux mis en cache par le scanner, jusqu'à ce qu'ils trouvent la prochaine valeur non-délimiteur (jeton). Merci à cela pour une entrée comme du codeScanner#nextType
"42\r\n\r\n321\r\n\r\n\r\nfoobar"
int num1 = sc.nextInt();
int num2 = sc.nextInt();
String name = sc.next();
sera en mesure d'attribuer correctement num1=42
num2=321
name=foobar
.
Au lieu de l' input.nextLine()
utiliser input.next()
, cela devrait résoudre le problème.
Code modifié:
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();
}
Si vous souhaitez lire à la fois des chaînes et des entiers, une solution consiste à utiliser deux scanners:
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();
Si vous voulez numériser rapidement l'entrée sans vous perdre dans la méthode nextLine () de la classe Scanner, utilisez le scanner d'entrée personnalisé pour cela.
Code:
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;
}
}
Avantages:
- Analyse l'entrée plus rapidement que BufferReader
- Réduit la complexité du temps
- Vide le tampon pour chaque entrée suivante
Méthodes:
- scanChar () - scanne un seul caractère
- scanInt () - scan Integer value
- scanLong () - scan Long valeur
- scanString () - scan Valeur de la chaîne
- scanDouble () - scan Double valeur
- scanInt (int [] array) - analyse le tableau complet (Integer)
- scanLong (long [] array) - scanne le tableau complet (long)
Utilisation:
- Copiez le code donné sous votre code java.
- Initialiser un objet pour une classe donnée
ScanReader sc = new ScanReader(System.in);
3. Importez les classes nécessaires:
import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream;
4. Lancez IOException à partir de votre méthode principale pour gérer l'exception 5. Utilisez les méthodes fournies. 6. Profitez
Exemple :
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....
Afin d'éviter le problème, utilisez nextLine();
immédiatement après nextInt();
car cela aide à vider la mémoire tampon. Lorsque vous appuyez sur ENTER
la nextInt();
ne capture pas la nouvelle ligne et par conséquent, permet de sauter le Scanner
code plus tard.
Scanner scanner = new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
sc.nextLine()
est mieux par rapport à l'analyse de l'entrée. Parce que ce sera bon en termes de performances.
Je suppose que je suis assez en retard à la fête.
Comme indiqué précédemment, appeler input.nextLine()
après avoir obtenu votre valeur int résoudra votre problème. La raison pour laquelle votre code n'a pas fonctionné était qu'il n'y avait rien d'autre à stocker à partir de votre entrée (où vous avez entré l'int) string1
. Je vais juste apporter un peu plus de lumière sur l'ensemble du sujet.
Considérez nextLine () comme la plus étrange parmi les méthodes nextFoo () de la classe Scanner. Prenons un exemple rapide. Disons que nous avons deux lignes de code comme celles ci-dessous:
int firstNumber = input.nextInt();
int secondNumber = input.nextInt();
Si nous saisissons la valeur ci-dessous (comme une seule ligne d'entrée)
54 234
La valeur de notre firstNumber
et de la secondNumber
variable devient respectivement 54 et 234. La raison pour laquelle cela fonctionne de cette façon est qu'un nouveau saut de ligne ( c'est-à-dire \ n ) N'EST PAS généré automatiquement lorsque la méthode nextInt () prend les valeurs. Il prend simplement le "prochain int" et continue . C'est la même chose pour le reste des méthodes nextFoo () à l'exception de nextLine ().
nextLine () génère un nouveau saut de ligne immédiatement après avoir pris une valeur; c'est ce que @RohitJain veut dire en disant que le nouveau saut de ligne est "consommé".
Enfin, la méthode next () prend simplement la chaîne la plus proche sans générer de nouvelle ligne; cela en fait la méthode préférentielle pour prendre des chaînes distinctes dans la même ligne unique.
J'espère que cela aide .. Joyeux codage!
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);
}
Utilisez 2 objets scanner au lieu d'un
Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();
si j'attends une entrée non vide
public static Function<Scanner,String> scanLine = (scan -> {
String s = scan.nextLine();
return( s.length() == 0 ? scan.nextLine() : s );
});
utilisé dans l'exemple ci-dessus:
System.out.println("Enter numerical value");
int option = input.nextInt(); // read numerical value from input
System.out.println("Enter 1st string");
String string1 = scanLine.apply( input ); // read 1st string
System.out.println("Enter 2nd string");
String string2 = scanLine.apply( input ); // read 2nd string
Dans l'un de mes cas d'utilisation, j'ai eu le scénario de lire une valeur de chaîne précédée de quelques valeurs entières . J'ai dû utiliser une " boucle for / while " pour lire les valeurs. Et aucune des suggestions ci-dessus n'a fonctionné dans ce cas.
Utiliser input.next()
au lieu de input.nextLine()
résoudre le problème. J'espère que cela pourrait être utile pour ceux qui ont affaire à un scénario similaire.
Comme les nextXXX()
méthodes ne lisent pas newline
, sauf nextLine()
. Nous pouvons ignorer la newline
lecture de n'importe quelle non-string
valeur ( int
dans ce cas) en utilisant scanner.skip()
comme ci-dessous:
Scanner sc = new Scanner(System.in);
int x = sc.nextInt();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(x);
double y = sc.nextDouble();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(y);
char z = sc.next().charAt(0);
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(z);
String hello = sc.nextLine();
System.out.println(hello);
float tt = sc.nextFloat();
sc.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
System.out.println(tt);
Utilisez ce code, il résoudra votre problème.
System.out.println("Enter numerical value");
int option;
option = input.nextInt(); // Read numerical value from input
input.nextLine();
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)
Pourquoi ne pas utiliser un nouveau scanner pour chaque lecture? Comme ci-dessous. Avec cette approche, vous ne serez pas confronté à votre problème.
int i = new Scanner(System.in).nextInt();
Le problème vient de la méthode input.nextInt () - elle ne lit que la valeur int. Ainsi, lorsque vous continuez à lire avec input.nextLine (), vous recevez la touche Entrée "\ n". Donc, pour sauter cela, vous devez ajouter le input.nextLine (). J'espère que cela devrait être clair maintenant.
Essayez-le comme ça:
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();