web-dev-qa-db-fra.com

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

J'utilise les méthodes Scanner, 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 de input.nextInt(). Si je le supprime, les fonctions string1 = input.nextLine() et string2 = input.nextLine() sont exécutées comme je le souhaite.

548
blekione

En effet, la méthode Scanner.nextInt ne lit pas le caractère newline créé en appuyant sur "Entrée". L’appel à Scanner.nextLine est donc restitué après la lecture de ce newline.

Vous rencontrez le même comportement lorsque vous utilisez Scanner.nextLine après Scanner.next() ou n’importe quelle méthode Scanner.nextFoo (sauf nextLine elle-même).

Solution de contournement:

  • Mettez un appel Scanner.nextLine après chaque Scanner.nextInt ou Scanner.nextFoo pour consommer le reste de cette ligne, y compris nouvelle ligne 

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Ou, mieux encore, lisez l'entrée Scanner.nextLine et convertissez-la au format adéquat dont vous avez besoin. Par exemple, vous pouvez convertir 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();
    
651
Rohit Jain

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 "\ n". Donc, pour ignorer cela, vous devez ajouter le input.nextLine () . J'espère que cela devrait être clair maintenant.

Essayez 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();
180
Prine

C'est parce que lorsque vous entrez un numéro, appuyez sur Enter, input.nextInt() ne consomme que le nombre, pas la "fin de ligne". Lorsque input.nextLine() est exécuté, il utilise la "fin de ligne" toujours dans le tampon depuis la première entrée.

Utilisez plutôt input.nextLine() immédiatement après input.nextInt()

74
Bohemian

Il semble y avoir beaucoup de 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 avoir appelé nextInt().

EDIT: comme @PatrickParker indiqué ci-dessous, cela provoquera une boucle infinie si l'utilisateur entre tout espace après le nombre. Voir leur réponse pour un meilleur modèle à utiliser avec skip: https://stackoverflow.com/a/42471816/143585

38
Denis Tulskiy

C'est parce que input.nextInt(); ne capture pas la nouvelle ligne. vous pouvez faire comme les autres proposés en ajoutant une input.nextLine(); dessous.
Vous pouvez aussi le faire en style C # et analyser une nextLine en un entier comme ceci: 

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

Cela fonctionne aussi bien et vous économise une ligne de code.

28
Electric Coffee

Ce que vous devez savoir:

  • le texte qui représente peu de lignes contient également des caractères non imprimables entre les lignes (nous les appelons séparateurs de lignes) 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, l’utilisateur peut taper sa réponse et quand il a terminé, il doit confirmer en quelque sorte _. Pour ce faire, l'utilisateur doit appuyer sur la touche "Entrée"/"Entrée" du clavier. 

    Ce qui est important, c’est que cette clé, qui permet de placer les données utilisateur dans entrée standard (représentée par System.in qui est lu par Scanner), envoie également des séparateurs de ligne dépendants du système d’exploitation (comme pour Windows \r\n). 

    Ainsi, lorsque vous demandez à l'utilisateur une valeur telle que age, et que l'utilisateur saisit 42 et que vous appuyez sur Entrée, l'entrée standard contiendra "42\r\n".

Problème

Scanner#nextInt (et les autres méthodes Scanner#nextType) n'autorisent pas Scanner à consommer ces séparateurs de ligne. Il les lira à partir de System.in (sinon, Scanner saurait qu’il n’ya plus de chiffres de l’utilisateur représentant la valeur age plutôt qu’un caractère blanc?), Ce qui les enlèvera de l’entrée standard, mais il y aura aussi cache ces séparateurs de lignes en interne. Ce dont nous devons nous rappeler, c’est que toutes les méthodes Scanner analysent toujours à partir du texte mis en cache. 

Maintenant, Scanner#nextLine() recueille et renvoie simplement tous les caractères jusqu'à ce qu'il trouve des séparateurs de ligne} _ (ou fin du flux). Mais comme les séparateurs de lignes après avoir lu le numéro sur la console se trouvent immédiatement dans le cache de Scanner, il renvoie String vide, ce qui signifie que Scanner n'a pu trouver aucun caractère avant ces séparateurs de lignes (ou fin de flux).
BTW nextLine également consomme 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 à la suite de nextLine

  • consomme le séparateur de ligne laissé par nextInt du cache des scanneurs par
    • appeler nextLine,
    • ou en appelant skip("\\R") pour laisser Scanner ignorer la pièce correspondant à \R qui représente un séparateur de ligne (plus d'informations sur \R: https://stackoverflow.com/a/31060125 )
  • n'utilisez jamais nextInt (ni next, ni aucune méthode nextTYPE). Lisez plutôt des lignes complètes de données ligne par ligne à l'aide de nextLine et analysez les numéros de chaque ligne (en supposant qu'une ligne ne contient qu'un seul nombre) vers le type approprié, tel que int via Integer.parseInt.

BTW: Scanner#nextType les méthodes peuvent ignorer les délimiteurs (par défaut, tous les espaces, comme les tabulations et les séparateurs de ligne), y compris ceux mis en cache par l'analyseur, jusqu'à ce qu'ils trouvent la prochaine valeur (non-délimiteur). Merci à cela pour l'entrée comme le code "42\r\n\r\n321\r\n\r\n\r\nfoobar" 

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

pourra assigner correctement num1=42num2=321name=foobar.

19
Pshemo

Au lieu de input.nextLine(), utilisez 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();
}
7
Castaldi

Afin d'éviter le problème, utilisez nextLine(); immédiatement après nextInt();, car cela aide à vider le tampon. Lorsque vous appuyez sur ENTER, la nextInt(); ne capture pas la nouvelle ligne et par conséquent, ignore le code Scanner ultérieurement. 

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

Si vous souhaitez numériser une entrée rapidement sans vous embrouiller dans la méthode nextLine () de la classe Scanner, utilisez Scanneur d'entrée personnalisé. 

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:

  • Scanne l'entrée plus rapidement que BufferReader 
  • Réduit la complexité du temps
  • Vide le tampon pour chaque entrée suivante

Les méthodes:

  • scanChar () - analyse un seul caractère
  • scanInt () - analyse la valeur entière
  • scanLong () - valeur d'analyse longue
  • scanString () - valeur d'analyse de chaîne
  • scanDouble () - scan Double valeur
  • scanInt (int [] array) - analyse le tableau complet (entier)
  • scanLong (long [] array) - analyse l'ensemble du tableau (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. Importer 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 Exception 5. Utiliser les méthodes fournies . 6. Prendre plaisir

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

Si vous voulez lire les chaînes et les ints, 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();
5
André Valenti

sc.nextLine() est préférable à l'analyse syntaxique de l'entrée ..__Parce que les performances seront optimales.

5
shankar upadhyay

Je suppose que je suis assez tard pour 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é est qu'il n'y avait rien d'autre à stocker de votre entrée (où vous avez entré l'int) dans string1. Je vais juste apporter un peu plus de lumière sur l'ensemble du sujet.

Considérez nextLine () comme l'intrus 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 entrons la valeur ci-dessous (comme une seule ligne d’entrée)

54 234

Les valeurs de nos variables firstNumber et secondNumber deviennent respectivement 54 et 234. Cela s’explique par le fait qu’un nouveau saut de ligne (i.e\n)IS NOTest généré automatiquement lorsque la méthode nextInt () prend les valeurs. Il prend simplement le "next int" et continue. C'est la même chose pour le reste des méthodes nextFoo () sauf 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 la nouvelle ligne est "consommée".

Enfin, la méthode next () prend simplement la chaîne la plus proche, String without générant une nouvelle ligne; cela en fait la méthode préférentielle pour prendre des chaînes séparées au sein d'une même ligne.

J'espère que cela aide .. Joyeux codage!

1
Taslim Oseni

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();
0
Harsh Shah
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);
    }
0
Neeraj Gahlawat