Le scanner ignore nextLine () après avoir utilisé next () ou nextFoo ()?

Oct 27 2012

J'utilise les Scannermé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

898 RohitJain Oct 27 2012 at 23:39

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.nextLineafter Scanner.next()ou n'importe quelle Scanner.nextFoométhode (sauf nextLineelle-même).

Solution de contournement:

  • Soit mettre un Scanner.nextLineappel après chacun, Scanner.nextIntsoit Scanner.nextFooconsommer le reste de cette ligne, y compris la nouvelle ligne

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Ou, mieux encore, lisez l'entrée Scanner.nextLineet 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();
    
222 Prine Aug 14 2011 at 19:24

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();
85 Bohemian Aug 14 2011 at 19:25

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()

51 DenisTulskiy Mar 23 2014 at 23:35

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

37 ElectricCoffee Feb 24 2013 at 05:01

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.

28 Pshemo Oct 10 2016 at 05:51

TL; DR À utiliser scanner.skip("\\R")avant chaque scanner.newLine()appel, qui est exécuté après:

  • scanner.next()
  • scanner.next*TYPE*()méthode, comme scanner.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.inlaquelle 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#nextTypeSystem.inage

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 nextIntcache des scanners par
  • appeler nextLine,
  • ou une manière plus lisible de l' OMI serait d'appeler skip("\\R")ou skip("\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(ni next, ni aucune nextTYPEméthode) du tout. Au lieu de cela, lisez des données entières ligne par ligne en utilisant nextLineet analysez les nombres de chaque ligne (en supposant qu'une ligne ne contient qu'un seul nombre) dans un type approprié comme intvia Integer.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.

17 Castaldi Jul 23 2014 at 17:20

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();
}
16 AndréWillikValenti Jun 21 2017 at 01:52

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();
13 NIKUNJKHOKHAR Jun 16 2017 at 15:12

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:

  1. Copiez le code donné sous votre code java.
  2. 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....
12 UrvashiGupta Nov 17 2016 at 07:51

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 ENTERla nextInt();ne capture pas la nouvelle ligne et par conséquent, permet de sauter le Scannercode plus tard.

Scanner scanner =  new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
10 shankarupadhyay Sep 14 2017 at 17:16

sc.nextLine()est mieux par rapport à l'analyse de l'entrée. Parce que ce sera bon en termes de performances.

6 TaslimOseni Jan 07 2018 at 17:33

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 firstNumberet de la secondNumbervariable 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!

5 NeerajGahlawat Jul 30 2017 at 10:48
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);
    }
5 HarshShah Jan 17 2019 at 02:24

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();
4 Kaplan Oct 02 2019 at 00:20

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
4 Giri Jan 24 2020 at 18:32

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.

4 SandeepKumar Dec 18 2019 at 16:08

Comme les nextXXX()méthodes ne lisent pas newline, sauf nextLine(). Nous pouvons ignorer la newlinelecture de n'importe quelle non-stringvaleur ( intdans 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);
2 JeewanthaLahiru Mar 08 2020 at 22:19

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)
TobiasJohansson Mar 13 2015 at 18:06

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();
PallavKhare Nov 22 2020 at 13:59

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();