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

Do odczytu danych wejściowych używam metod Scanner nextInt() i nextLine().

Wygląda to 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 polega na tym, że po wpisaniu wartości liczbowej pierwsza input.nextLine() jest pomijana, a druga input.nextLine() jest wykonywana, tak że moje wyjście wygląda tak:

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 leży w użyciu input.nextInt(). Jeśli go usunę, to zarówno string1 = input.nextLine(), jak i string2 = input.nextLine() zostaną wykonane tak, jak chcę.

Author: Lii, 2012-10-27

15 answers

To dlatego, że Scanner.nextInt metoda nie pobiera znaku ostatniego newline z twojego wejścia, a zatem newline jest pobierana w następnym wywołaniu do Scanner.nextLine.

Podobne zachowanie napotkasz, gdy użyjesz Scanner.nextLine po Scanner.next() lub dowolną metodą Scanner.nextFoo (z wyjątkiem samej metody nextLine).

Obejście:

  • Albo wystrzelić puste Scanner.nextLine wywołanie po Scanner.nextInt lub Scanner.nextFoo, aby pochłonąć resztę tej linii w tym newline

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Lub, byłoby jeszcze lepiej, gdybyś odczytał dane wejściowe przez Scanner.nextLine i przekonwertował dane wejściowe do odpowiedniego formatu, którego potrzebujesz. Dla przykładu, do liczby całkowitej za pomocą Integer.parseInt(String) metoda.

    int option = 0;
    try {
        option = Integer.parseInt(input.nextLine());
    } catch (NumberFormatException e) {
        e.printStackTrace();
    }
    String str1 = input.nextLine();
    
 597
Author: Rohit Jain,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-16 02:10:50

Problem jest z wejściem .metoda nextInt () - odczytuje tylko wartość int. Więc kiedy kontynuujesz Czytanie z wejściem.nextLine () otrzymasz klawisz Enter "\n". Aby to pominąć, musisz dodać input.nextLine () . Mam nadzieję, że teraz to będzie 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();
 170
Author: Prine,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-12-29 06:57:36

To dlatego, że po wpisaniu liczby naciśnij Enter, input.nextInt() zużywa tylko liczbę, a nie "koniec linii". Gdy input.nextLine() zostanie uruchomiony, "koniec linii" będzie nadal w buforze od pierwszego wejścia.

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

 63
Author: Bohemian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-08-14 12:25:35

Wydaje się być wiele pytań na ten temat z java.util.Scanner. Myślę, że bardziej czytelnym / idiomatycznym rozwiązaniem byłoby wywołanie scanner.skip("[\r\n]+"), aby zrzucić znaki nowej linii po wywołaniu nextInt().

EDIT: jak @PatrickParker zauważył poniżej, spowoduje to nieskończoną pętlę, jeśli użytkownik wprowadzi białe znaki po numerze. Zobacz ich odpowiedź, aby uzyskać lepszy wzór do użycia z pominięciem: https://stackoverflow.com/a/42471816/143585

 34
Author: Denis Tulskiy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:41

Robi to, ponieważ input.nextInt(); nie przechwytuje nowej linii. możesz zrobić tak jak inne proponowane przez dodanie input.nextLine(); pod spodem.
Alternatywnie możesz to zrobić w stylu C# i przetworzyć następną linię do liczby całkowitej w następujący sposób:

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

To działa równie dobrze, i oszczędza Ci wiersz kodu.

 24
Author: Electric Coffee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-23 22:01:23

Rzeczy, które musisz wiedzieć:

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

    • carriage return (CR - w literałach łańcuchowych reprezentowanych jako "\r")
    • line feed (LF - w literałach łańcuchowych reprezentowanych jako "\n")
  • Kiedy czytasz dane z konsoli, pozwala to użytkownikowi na wpisanie odpowiedzi, a po jej zakończeniu musi jakoś potwierdź ten fakt. Aby to zrobić, użytkownik musi nacisnąć klawisz"enter"/" return " na klawiaturze.

    Ważne jest to, że ten klucz oprócz zapewnienia umieszczania danych użytkownika na standardowym wejściu (reprezentowanym przez System.in, który jest odczytywany przez Scanner) wysyła po nim również separatory linii zależnych od systemu operacyjnego (jak Dla Windows \r\n).

    Więc gdy zapytasz użytkownika o wartość jak age, i typ użytkownika 42 i naciśnie enter, standardowe wejście będzie zawierać "42\r\n".

Problem

Scanner#nextInt (i inne Scanner#nextType metody) nie pozwalają skanerowi na zużywanie tych separatorów linii. Odczyta je z System.in (skąd inaczej Skaner wiedziałby, że nie ma więcej cyfr od użytkownika, które reprezentują wartość age niż białe znaki?), które usunie je ze standardowego wejścia, ale będzie również buforować te separatory linii wewnętrznie. Musimy pamiętać, że wszystkie metody skanowania są zawsze skanowanie począwszy od tekstu w pamięci podręcznej.

Teraz Scanner#nextLine() po prostu zbiera i zwraca wszystkie znaki , dopóki nie znajdzie separatorów linii (lub końca strumienia). Ponieważ jednak separatory linii po odczytaniu numeru z konsoli znajdują się bezpośrednio w pamięci podręcznej skanera, zwraca pusty łańcuch, co oznacza, że skaner nie był w stanie znaleźć żadnego znaku przed tymi separatorami linii (lub końcem strumienia).
BTW nextLine również zużywa te separatory liniowe.

Rozwiązanie

Więc jeśli chcesz poprosić o liczbę, a następnie o całą linię, unikając pustego ciągu jako wyniku nextLine, albo

  • użyj separatora linii pozostawionego przez nextInt z pamięci podręcznej skanerów przez
    • wywołanie nextLine,
    • lub przez wywołanie skip("\\R") aby skaner pominął część dopasowaną przez \R, która reprezentuje separator linii (więcej informacji o \R: https://stackoverflow.com/a/31060125 )
  • nie używaj nextInt (ani next, ani żadnych nextTYPE metod) w ogóle. Zamiast tego odczytaj całe dane linia po linii za pomocą nextLine i parsuj liczby z każdej linii (zakładając, że jedna linia zawiera tylko jedną liczbę) do odpowiedniego typu, takiego jak int poprzez Integer.parseInt.

BTW: Scanner#nextType metody mogą pomijać ograniczniki (domyślnie wszystkie białe spacje, takie jak tabulatory, separatory linii) łącznie z tymi buforowanymi przez skaner, dopóki nie znajdą następnej wartości nie-ogranicznika (token). Dzięki temu za wprowadzenie kodu "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 prawidłowo przypisać num1=42 num2=321 name=foobar.

 16
Author: Pshemo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-15 16:29:11

Zamiast input.nextLine() Użyj input.next(), to powinno 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();
}
 5
Author: Castaldi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-23 10:31:22

Aby uniknąć problemu, użyj nextLine(); natychmiast po nextInt();, ponieważ pomaga to w wyczyszczeniu bufora. Po naciśnięciu ENTER nextInt(); nie wychwytuje nowej linii, a tym samym pomija kod Scanner później.

Scanner scanner =  new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
 5
Author: Urvashi Gupta,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 00:51:29

Jeśli chcesz szybko przeskanować dane wejściowe bez pomyłki w metodzie Scanner class nextLine (), Użyj dla niej 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 wejście szybciej niż BufferReader
  • Zmniejsza Złożoność Czasu
  • spłukuje bufor dla każdego następnego wejścia

Metody:

  • scanChar () - skanowanie pojedynczego znaku
  • scanInt () - wartość całkowita skanowania
  • scanLong () - Scan Long wartość
  • scanString () - scan String value
  • scanDouble () - Skanuj podwójną wartość
  • scanInt(int [] array) - scans complete Array (Integer)
  • scanLong ( long [] array) - skanuje kompletną tablicę (Long)

Użycie:

  1. skopiuj podany kod poniżej kodu java.
  2. Initialise obiekt dla podanej klasy

ScanReader sc = new ScanReader(System.in); 3. Import niezbędnych klas :

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Throw IOException from your main method to handle Exception 5. Użyj Podanych Metod. 6. Enjoy

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....
 5
Author: NIKUNJ KHOKHAR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-16 08:12:55

Jeśli chcesz odczytać zarówno ciągi znaków, jak i ints, 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();
 3
Author: André Valenti,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-20 18:52:41

sc.nextLine() jest lepszy w porównaniu do parsowania danych wejściowych. Ponieważ wydajność wise to będzie dobre.

 2
Author: shankar Dayal upadhyay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
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
Author: Neeraj Gahlawat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-30 03:48:25

Moje testy dały takie same wyniki jak Prine, jednak pomyślałem o dość prostym obejściu:

Użycie BufferedReader#nextLine(), gdzie można Scanner#readLine(), pozwala uniknąć tego błędu. Możesz nawet napisać własne opakowanie skanera, aby zastąpić funkcję readLine skanera za pomocą funkcji BufferedReader nextLine.

 0
Author: SamJakob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-24 00:23:40

Chyba jestem spóźniony na imprezę..

Jak wcześniej wspomniano, wywołanie {[1] } po otrzymaniu 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 przechowywania z twojego wejścia (gdzie wprowadziłeś int) do string1. Rzucę trochę więcej światła na cały temat.

Rozważmy nextline () jako nieparzystą spośród metod nextFoo() w klasie skanera. Weźmy szybki przykład.. Załóżmy, że mamy dwie linie kodu, takie jak te poniżej:

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

Jeśli wprowadzimy wartość poniżej (jako pojedynczy wiersz wejścia)

54 234

Wartość naszej zmiennej firstNumber i secondNumber wynosi odpowiednio 54 i 234. Powodem, dla którego to działa w ten sposób jest to, że nowy kanał linii ( tj.) nie jest generowane automatycznie, gdy metoda nextInt() przyjmuje wartości. Po prostu trwa "next int" i idzie dalej. To jest taka sama dla pozostałych metod nextfoo () z wyjątkiem nextline ().

NextLine () generuje nowy kanał linii natychmiast po pobraniu wartości; to właśnie @RohitJain ma na myśli mówiąc, że nowy kanał linii jest "zużyty".

Wreszcie, metoda next () po prostu pobiera najbliższy Ciąg BEZ generowania nowej linii; to sprawia, że jest to preferencyjna metoda pobierania oddzielnych ciągów w obrębie tej samej pojedynczej linii.

Mam nadzieję, że to pomoże.. Wesołego kodowania!
 0
Author: Taslim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-07 10:40:26

Dlaczego nie użyć nowego skanera do każdego odczytu? Jak poniżej. Dzięki takiemu podejściu nie skonfrontujesz się ze swoim problemem.

int i = new Scanner(System.in).nextInt();
 -2
Author: Tobias Johansson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-03-13 11:06:54