Le Scanner saute nextLine() après avoir utilisé next () ou nextFoo ()?

j'utilise les Scanner méthodes nextInt() et nextLine() pour lire l'entrée.

il 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, le premier input.nextLine() est sauté et le second input.nextLine() est exécuté, 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 supprimer, puis les deux string1 = input.nextLine() et string2 = input.nextLine() sont exécutés comme je veux qu'ils soient.

501
demandé sur Lii 2012-10-27 20:37:01

15 réponses

c'est parce que la méthode Scanner.nextInt ne consomme pas le caractère dernier newline de votre entrée, et donc que newline est consommé dans le prochain appel à Scanner.nextLine .

vous rencontrerez le même comportement lorsque vous utilisez Scanner.nextLine après Scanner.next() ou toute méthode Scanner.nextFoo (sauf nextLine elle-même).

contournement:

  • soit lancer un blanc Scanner.nextLine appeler après Scanner.nextInt ou Scanner.nextFoo pour consommer le reste de cette ligne, y compris newline 1519220920"

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Ou, ce serait encore mieux, si vous lisez l'entrée Scanner.nextLine et de convertir votre entrée pour le format approprié vous avez besoin. Pour des exemples, à un entier en utilisant Integer.parseInt(String) la méthode.

    int option = 0;
    try {
        option = Integer.parseInt(input.nextLine());
    } catch (NumberFormatException e) {
        e.printStackTrace();
    }
    String str1 = input.nextLine();
    
597
répondu Rohit Jain 2017-10-16 02:10:50

le problème est avec l'entrée .nextInt () méthode-il lit seulement la valeur int. Ainsi, lorsque vous continuer la lecture.nextLine () vous recevez la touche "\n" Enter. Donc, pour sauter ceci, vous devez ajouter l'entrée .nextLine () . Espérons 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();
170
répondu Prine 2017-12-29 06:57:36

c'est parce que quand vous entrez un nombre puis appuyez sur entrer , input.nextInt() consomme seulement le nombre, pas la"fin de ligne". Lorsque input.nextLine() s'exécute, il consomme la" fin de ligne " toujours dans le tampon à partir de la première entrée.

à la place, utilisez input.nextLine() immédiatement après input.nextInt()

63
répondu Bohemian 2011-08-14 12:25:35

il semble y avoir beaucoup de questions à ce sujet 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 newline après avoir appelé nextInt() .

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

34
répondu Denis Tulskiy 2017-05-23 12:10:41

il fait cela parce que input.nextInt(); ne capture pas la nouvelle ligne. vous pouvez faire comme les autres proposées en ajoutant un input.nextLine(); en dessous.

Alternativement vous pouvez le faire c # style et analyser un nextLine à un entier comme ainsi:

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

faire cela fonctionne aussi bien, et il vous sauve une ligne de code.

24
répondu Electric Coffee 2013-02-23 22:01:23

choses que vous devez savoir:

  • texte qui représente peu de lignes contient également des caractères non imprimables entre les lignes (nous les appelons séparateurs de ligne) comme

    • retour de chariot (CR - dans les littéraux de Chaîne représentée comme "\r" )
    • saut de ligne (LF - dans les littéraux de Chaîne représentée comme "\n" )
  • quand vous lisez les données de la console, il permet à l'utilisateur de taper sa réponse et quand il est fait, il a besoin de en quelque sorte confirmer ce fait. Pour ce faire, l'utilisateur doit appuyer sur la touche "entrer"/touche"retour" sur le clavier.

    ce qui est important est que cette clé en plus d'assurer le placement des données de l'utilisateur à entrée standard (représenté par System.in qui est lu par Scanner ) envoie également les séparateurs de ligne dépendants de L'OS (comme pour Windows \r\n ) après lui.

    Ainsi , lorsque vous demandez à l'utilisateur une valeur comme age , et que les types d'utilisateurs 42 et les presses entrent, l'entrée standard contiendra "42\r\n" .

problème

Scanner#nextInt (et d'autres méthodes Scanner#nextType ) ne permet pas au Scanner de consommer ces séparateurs de ligne. Il les lira de System.in (comment Scanner sauriez-vous qu'il n'y a pas plus de chiffres de l'utilisateur qui représentent age valeur que face espace blanc?) qui va les supprimer de l'entrée standard, mais il sera également cache ces séparateurs de ligne en interne . Ce que nous devons nous rappeler, c'est que toutes les méthodes de Scanner sont toujours en train de numériser à partir du texte caché.

maintenant Scanner#nextLine() recueille simplement et renvoie tous les caractères jusqu'à il trouve les séparateurs de ligne (ou fin de flux). Mais puisque les séparateurs de ligne après avoir lu le numéro de la console se trouvent immédiatement dans le cache du Scanner, il retourne la chaîne vide, ce qui signifie que le Scanner n'a pas pu trouver de caractère avant ces séparateurs de ligne (ou fin de flux).

BTW nextLine aussi consomme ces séparateurs de ligne.

Solution

donc quand vous voulez pour demander le nombre et ensuite pour la ligne entière tout en évitant cette chaîne vide à la suite de nextLine , soit

  • consommer de séparateur de ligne à gauche par nextInt à partir de Scanners cache par
    • appelant nextLine ,
    • ou en appelant skip("\R") pour laisser le Scanner sauter la partie correspondant à \R qui représente le séparateur de ligne (plus d'informations sur \R : https://stackoverflow.com/a/31060125 )
  • n'utilisez pas nextInt (ni next , ni aucune méthode nextTYPE ). Au lieu de cela, Lire la totalité des données ligne par ligne en utilisant nextLine et les numéros d'analyse de chaque ligne (en supposant qu'une ligne ne contient qu'un seul numéro) au type approprié comme int via Integer.parseInt .

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

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

sera en mesure d'attribuer correctement num1=42 num2=321 name=foobar .

16
répondu Pshemo 2018-08-15 16:29:11

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();
}
5
répondu Castaldi 2014-07-23 10:31:22

pour éviter l'émission, utilisez nextLine(); immédiatement après nextInt(); car il aide à éliminer le tampon. Lorsque vous appuyez sur ENTER le nextInt(); ne capture pas la nouvelle ligne et donc, saute le code Scanner plus tard.

Scanner scanner =  new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
5
répondu Urvashi Gupta 2016-11-17 00:51:29

si vous voulez numériser l'entrée rapidement sans se confondre dans la classe de Scanner méthode nextLine (), 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:

  • scanne L'entrée plus rapidement que BufferReader
  • Réduit La Complexité Du Temps
  • tampon de rinçage pour chaque entrée suivante

méthodes:

  • scanChar() - scan caractère unique
  • scanInt() - scan valeur entière
  • scanLong() - analyse Long de la valeur
  • scanString() - analyse de la Chaîne de valeur
  • scanDouble () - scan Double value
  • scanInt(int tableau []) - analyse complète Array(Integer)
  • scanLong(long tableau []) - analyse complète de la Matrice de(Long)

Utilisation :

  1. Copiez le Code indiqué sous votre code java.
  2. initialiser L'objet pour une classe donnée

ScanReader sc = new ScanReader(System.in); 3. Catégories nécessaires à l'importation:

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. Profiter de

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....
5
répondu NIKUNJ KHOKHAR 2017-06-16 08:12:55

si vous voulez lire à la fois les chaînes et les ints, une solution est d'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();
3
répondu André Valenti 2017-06-20 18:52:41

sc.nextLine() est meilleur que l'analyse de l'entrée. Parce que la performance sage ce sera bon.

2
répondu shankar Dayal upadhyay 2017-09-14 10:45:34
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
répondu Neeraj Gahlawat 2017-07-30 03:48:25

mes tests ont donné les mêmes résultats que Prine, mais j'ai pensé à une solution assez simple:

en utilisant BufferedReader#nextLine() , où vous voulez Scanner#readLine() , évite ce bug. Vous pouvez même écrire votre propre wrapper de Scanner pour outrepasser la fonction readline de Scanner avec la fonction nextLine de BufferedReader.

0
répondu SamJakob 2017-11-24 00:23:40

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

prendre en considération nextLine() comme l'intrus parmi les nextFoo () méthodes dans la classe de 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 (en une seule ligne d'entrée)

54 234

la valeur de nos variables firstNumber et secondNumber devient respectivement 54 et 234. La raison pour laquelle cela fonctionne de cette façon est parce qu'une nouvelle ligne d'alimentation ( I. e \n ) N'est pas généré automatiquement lorsque la méthode nextInt() prend les valeurs. Il prend simplement le "int suivant" et se déplace sur. C'est la même chose pour le reste des méthodes nextFoo() sauf nextLine().

nextLine () génère une nouvelle alimentation de ligne immédiatement après avoir pris une valeur; c'est ce que @RohitJain signifie en disant que la nouvelle alimentation de ligne est "consommée".

enfin, la méthode next() prend simplement la chaîne la plus proche sans générant une nouvelle ligne; ce qui en fait la Méthode préférentielle pour prendre des chaînes séparées à l'intérieur de la même ligne simple.

j'espère que cela aidera.. Joyeux codage!

0
répondu Taslim 2018-01-07 10:40:26

pourquoi ne pas utiliser un nouveau Scanner pour chaque lecture? Comme ci-dessous. Avec cette approche, vous n'affronterez pas votre problème.

int i = new Scanner(System.in).nextInt();
-2
répondu Tobias Johansson 2015-03-13 11:06:54