Skaner pomija nextLine () po użyciu next () lub nextFoo ()?

Oct 27 2012

Używam Scannermetod nextInt()i nextLine()do czytania danych wejściowych.

To wygląda tak:

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)

Problem w tym, że po wpisaniu wartości liczbowej pierwsza input.nextLine()jest pomijana a druga input.nextLine()wykonywana, dzięki czemu moje wyjście wygląda następująco:

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

Przetestowałem moją aplikację i wygląda na to, że problem tkwi w używaniu input.nextInt(). Jeśli go usunę, oba string1 = input.nextLine()i string2 = input.nextLine()zostaną wykonane tak, jak chcę.

Odpowiedzi

898 RohitJain Oct 27 2012 at 23:39

Dzieje się tak, ponieważ Scanner.nextIntmetoda nie odczytuje znaku nowej linii w danych wejściowych utworzonych przez naciśnięcie klawisza „Enter”, a więc wywołanie Scanner.nextLinepowraca po przeczytaniu tej nowej linii .

Podobne zachowanie napotkasz, gdy użyjesz Scanner.nextLineafter Scanner.next()lub dowolnej Scanner.nextFoometody (z wyjątkiem nextLinesiebie).

Obejście problemu:

  • Albo umieścić Scanner.nextLinepołączenia po każdym Scanner.nextIntlub Scanner.nextFoozużywają resztę tej linii w tym nowej linii

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Lub, jeszcze lepiej, przeczytaj dane wejściowe Scanner.nextLinei przekonwertuj je na odpowiedni format, którego potrzebujesz. Na przykład można przekonwertować na liczbę całkowitą przy użyciu Integer.parseInt(String)metody 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

Problem dotyczy metody input.nextInt () - odczytuje ona tylko wartość int. Więc kiedy będziesz kontynuować czytanie za pomocą input.nextLine (), otrzymasz klawisz "\ n" Enter. Aby to pominąć, musisz dodać metodę input.nextLine () . Mam nadzieję, że to powinno być teraz jasne.

Spróbuj tak:

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

Dzieje się tak, ponieważ kiedy wpisujesz liczbę, a następnie naciskasz Enter, input.nextInt()zużywa tylko liczbę, a nie „koniec wiersza”. Podczas input.nextLine()wykonywania zużywa „koniec wiersza” znajdujący się nadal w buforze z pierwszego wejścia.

Zamiast tego użyj input.nextLine()natychmiast poinput.nextInt()

51 DenisTulskiy Mar 23 2014 at 23:35

Wydaje się, że istnieje wiele pytań dotyczących tego problemu java.util.Scanner. Myślę, że bardziej czytelnym / idiomatycznym rozwiązaniem byłoby wywołanie scanner.skip("[\r\n]+")po wywołaniu wszelkich znaków nowej linii nextInt().

EDYCJA: jak @PatrickParker zauważył poniżej, spowoduje to nieskończoną pętlę, jeśli użytkownik wprowadzi jakąkolwiek białą spację po liczbie. Zobacz ich odpowiedź, aby uzyskać lepszy wzorzec do użycia z pomijaniem:https://stackoverflow.com/a/42471816/143585

37 ElectricCoffee Feb 24 2013 at 05:01

Robi to, ponieważ input.nextInt();nie przechwytuje nowej linii. możesz zrobić jak inne proponowane, dodając input.nextLine();pod spodem.
Alternatywnie możesz to zrobić w stylu C # i przeanalizować nextLine do liczby całkowitej, jak na przykład:

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

Działa to równie dobrze i pozwala zaoszczędzić wiersz kodu.

28 Pshemo Oct 10 2016 at 05:51

TL; DR Użyj scanner.skip("\\R")przed każdym scanner.newLine()wywołaniem, które jest wykonywane po:

  • scanner.next()
  • scanner.next*TYPE*()metoda, na przykład scanner.nextInt().

Co musisz wiedzieć:

  • tekst, który reprezentuje kilka linii, zawiera również niedrukowalne znaki między wierszami (nazywamy je separatorami linii), jak

  • powrót karetki (CR - w literałach String reprezentowanych jako "\r")

  • nowy wiersz (LF - w literałach ciągów reprezentowanych jako "\n")

  • kiedy czytasz dane z konsoli, pozwala to użytkownikowi wpisać swoją odpowiedź, a kiedy skończy, musi jakoś potwierdzić ten fakt. Aby to zrobić, użytkownik musi nacisnąć klawisz „enter” / „return” na klawiaturze.

Ważne jest to, że ten klucz, oprócz zapewnienia umieszczenia danych użytkownika na standardowym wejściu (reprezentowanym przez System.inktóre jest odczytywane Scanner), wysyła również \r\npo nim separatory linii zależne od systemu operacyjnego (jak w systemie Windows ).

Więc kiedy pytasz użytkownika o wartość taką jak age, a użytkownik wpisze 42 i naciśnie klawisz Enter, standardowe wejście będzie zawierać "42\r\n".

Problem

Scanner#nextInt(i inne metody) nie pozwalają Scanner zużywają tych separatorów. Odczyta je z (skąd inaczej Scanner wiedziałby, że nie ma więcej cyfr od użytkownika, które reprezentują wartość, niż stojące przed białymi znakami?), Co usunie je ze standardowego wejścia, ale także buforuje wewnętrznie te separatory linii . Musimy pamiętać, że wszystkie metody skanera zawsze skanują, zaczynając od tekstu z pamięci podręcznej.Scanner#nextTypeSystem.inage

Teraz Scanner#nextLine()po prostu zbiera i zwraca wszystkie znaki, aż znajdzie separatory wierszy (lub koniec strumienia). Ale ponieważ separatory linii po odczytaniu liczby z konsoli znajdują się natychmiast w pamięci podręcznej skanera, zwraca on pusty ciąg, co oznacza, że ​​Scanner nie był w stanie znaleźć żadnego znaku przed tymi separatorami linii (lub końcem strumienia).
BTW nextLinerównież zużywa te separatory linii.

Rozwiązanie

Więc jeśli chcesz zapytać o numer, a następnie na całej linii, unikając że pusty ciąg znaków w wyniku nextLine, albo

  • zużywa separator linii pozostawiony przez nextIntpamięć podręczną skanerów przez
  • dzwonienie nextLine,
  • lub IMO bardziej czytelnym sposobem byłoby wywołanie skip("\\R")lub skip("\r\n|\r|\n")zezwolenie Scannerowi na pominięcie części dopasowanej przez separator linii (więcej informacji na temat \R:https://stackoverflow.com/a/31060125)
  • w ogóle nie używaj nextInt(ani nextżadnych nextTYPEmetod). Zamiast tego czytaj całe dane wiersz po wierszu, używając nextLinei analizuj liczby z każdego wiersza (zakładając, że jeden wiersz zawiera tylko jedną liczbę) do odpowiedniego typu, takiego jak intvia Integer.parseInt.

BTW : metody mogą pomijać ograniczniki (domyślnie wszystkie białe znaki, takie jak tabulatory, separatory wierszy), w tym te buforowane przez skaner, aż znajdą następną wartość nie będącą ogranicznikiem (token). Dzięki temu wpisuje się jak kodScanner#nextType"42\r\n\r\n321\r\n\r\n\r\nfoobar"

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

będzie w stanie poprawnie przypisać num1=42 num2=321 name=foobar.

17 Castaldi Jul 23 2014 at 17:20

Zamiast input.nextLine()używać input.next(), powinno to rozwiązać problem.

Zmodyfikowany kod:

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

Jeśli chcesz odczytać zarówno ciągi, jak i int, rozwiązaniem jest użycie dwóch skanerów:

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

Jeśli chcesz szybko skanować dane wejściowe, nie dając się pomylić z metodą nextLine () klasy skanera, użyj do tego celu niestandardowego skanera wejściowego.

Kod :

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;
    }

}

Zalety :

  • Skanuje dane wejściowe szybciej niż BufferReader
  • Zmniejsza złożoność czasu
  • Opróżnia bufor przy każdym następnym wejściu

Metody:

  • scanChar () - skanuje pojedynczy znak
  • scanInt () - skan Wartość całkowita
  • scanLong () - scan Długa wartość
  • scanString () - skanuj wartość ciągu
  • scanDouble () - scan Podwójna wartość
  • scanInt (int [] array) - skanuje całą tablicę (Integer)
  • scanLong (long [] array) - skanuje całą tablicę (Long)

Stosowanie :

  1. Skopiuj podany kod poniżej kodu java.
  2. Zainicjuj obiekt dla danej klasy

ScanReader sc = new ScanReader(System.in); 3. Importuj niezbędne klasy:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Wyrzuć IOException z głównej metody, aby obsłużyć wyjątek. 5. Użyj dostarczonych metod. 6. Ciesz się

Przykład:

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

Aby uniknąć problemu, użyj nextLine();natychmiast po, nextInt();ponieważ pomaga w wyczyszczeniu bufora. Po naciśnięciu nie uchwycić nową linię, a więc pomija kod później.ENTERnextInt();Scanner

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()jest lepsza w porównaniu z analizowaniem danych wejściowych. Ponieważ pod względem wydajności będzie dobrze.

6 TaslimOseni Jan 07 2018 at 17:33

Chyba dość spóźniłem się na imprezę ..

Jak już wspomniano, zadzwonienie input.nextLine()po uzyskaniu wartości int rozwiąże problem. Powodem, dla którego twój kod nie działał, było to, że nie było nic innego do zapisania z twojego wejścia (gdzie wprowadziłeś int) do string1. Rzucę tylko trochę więcej światła na cały temat.

Rozważ metodę nextLine () jako nieparzystą spośród metod nextFoo () w klasie Scanner. Weźmy szybki przykład ... Powiedzmy, że mamy dwa wiersze kodu, takie jak te poniżej:

int firstNumber = input.nextInt();
int secondNumber = input.nextInt();

Jeśli wprowadzimy wartość poniżej (jako pojedyncza linia danych wejściowych)

54 234,

Wartości naszej firstNumberi secondNumberzmiennej wynoszą odpowiednio 54 i 234. Powodem, dla którego to działa w ten sposób, jest to, że nowy znak nowego wiersza ( tj. \ N ) NIE JEST automatycznie generowany, gdy metoda nextInt () przyjmuje wartości. Po prostu bierze „next int” i przechodzi dalej. To samo dotyczy pozostałych metod nextFoo () z wyjątkiem nextLine ().

nextLine () generuje nowy znak nowego wiersza natychmiast po pobraniu wartości; to właśnie @RohitJain ma na myśli mówiąc, że nowy wiersz jest „zużyty”.

Na koniec metoda next () po prostu pobiera najbliższy ciąg znaków bez generowania nowej linii; sprawia to, że jest to preferowana metoda pobierania oddzielnych ciągów w tej samej pojedynczej linii.

Mam nadzieję, że to pomoże ... Wesołego kodowania!

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

Użyj 2 skanerów zamiast jednego

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

jeśli oczekuję niepustych danych wejściowych

public static Function<Scanner,String> scanLine = (scan -> {
    String s = scan.nextLine();
    return( s.length() == 0 ? scan.nextLine() : s );
  });


użyte w powyższym przykładzie:

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

W jednym z moich przypadków użycia miałem scenariusz czytania wartości ciągu poprzedzonej kilkoma wartościami całkowitymi . Aby odczytać wartości, musiałem użyć pętlifor / while ”. I żadna z powyższych sugestii nie zadziałała w tym przypadku.

Używanie input.next()zamiast input.nextLine()naprawienia problemu. Mam nadzieję, że może to być pomocne dla osób, które mają do czynienia z podobnym scenariuszem.

4 SandeepKumar Dec 18 2019 at 16:08

Ponieważ nextXXX()metody nie czytają newline, z wyjątkiem nextLine(). Możemy pominąć newlinepo przeczytaniu dowolnej non-stringwartości ( intw tym przypadku), używając scanner.skip()jak poniżej:

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

Użyj tego kodu, aby rozwiązać problem.

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

Dlaczego nie używać nowego skanera do każdego odczytu? Jak poniżej. Dzięki takiemu podejściu nie zmierzysz się z problemem.

int i = new Scanner(System.in).nextInt();
PallavKhare Nov 22 2020 at 13:59

Problem dotyczy metody input.nextInt () - odczytuje ona tylko wartość int. Więc kiedy będziesz kontynuować czytanie za pomocą input.nextLine (), otrzymasz klawisz "\ n" Enter. Aby to pominąć, musisz dodać metodę input.nextLine (). Mam nadzieję, że to powinno być teraz jasne.

Spróbuj tak:

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