Máy quét đang bỏ qua nextLine () sau khi sử dụng next () hoặc nextFoo ()?

Oct 27 2012

Tôi đang sử dụng các Scannerphương pháp nextInt()nextLine()để đọc đầu vào.

Nó trông như thế này:

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)

Vấn đề là sau khi nhập giá trị số, giá trị đầu tiên input.nextLine()bị bỏ qua và giá trị thứ hai input.nextLine()được thực thi, do đó đầu ra của tôi trông giống như sau:

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

Tôi đã thử nghiệm ứng dụng của mình và có vẻ như vấn đề nằm ở việc sử dụng input.nextInt(). Nếu tôi xóa nó, thì cả hai string1 = input.nextLine()string2 = input.nextLine()đều được thực thi như tôi muốn.

Trả lời

898 RohitJain Oct 27 2012 at 23:39

Đó là bởi vì Scanner.nextIntphương thức không đọc tự dòng mới trong đầu vào của bạn được tạo bằng cách nhấn "Enter" và do đó lệnh gọi Scanner.nextLinetrả về sau khi đọc dòng mới đó .

Bạn sẽ gặp phải hành vi tương tự khi bạn sử dụng Scanner.nextLineafter Scanner.next()hoặc bất kỳ Scanner.nextFoophương thức nào (ngoại trừ nextLinechính nó).

Cách giải quyết:

  • Thực hiện Scanner.nextLinecuộc gọi sau mỗi cuộc gọi Scanner.nextInthoặc Scanner.nextFoosử dụng phần còn lại của dòng đó bao gồm cả dòng mới

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • Hoặc, tốt hơn nữa, hãy đọc thông tin đầu vào Scanner.nextLinevà chuyển đổi đầu vào của bạn sang định dạng phù hợp mà bạn cần. Ví dụ, bạn có thể chuyển đổi thành một số nguyên bằng Integer.parseInt(String)phương pháp.

    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

Vấn đề là với phương thức input.nextInt () - nó chỉ đọc giá trị int. Vì vậy, khi bạn tiếp tục đọc với input.nextLine (), bạn sẽ nhận được phím Enter "\ n". Vì vậy, để bỏ qua điều này, bạn phải thêm input.nextLine () . Hy vọng điều này sẽ rõ ràng ngay bây giờ.

Hãy thử nó như thế:

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

Đó là bởi vì khi bạn nhập một số sau đó nhấn Enter, input.nextInt()chỉ tiêu thụ số đó, không phải "cuối dòng". Khi input.nextLine()thực thi, nó sử dụng "cuối dòng" vẫn còn trong bộ đệm từ đầu vào đầu tiên.

Thay vào đó, hãy sử dụng input.nextLine()ngay sauinput.nextInt()

51 DenisTulskiy Mar 23 2014 at 23:35

Có vẻ như có nhiều câu hỏi về vấn đề này với java.util.Scanner. Tôi nghĩ rằng một giải pháp dễ đọc / thành ngữ hơn sẽ là gọi scanner.skip("[\r\n]+")để bỏ bất kỳ ký tự dòng mới nào sau khi gọi nextInt().

CHỈNH SỬA: như @PatrickParker đã lưu ý bên dưới, điều này sẽ gây ra vòng lặp vô hạn nếu người dùng nhập bất kỳ khoảng trắng nào sau số. Xem câu trả lời của họ để biết mẫu tốt hơn để sử dụng với bỏ qua: https://stackoverflow.com/a/42471816/143585

37 ElectricCoffee Feb 24 2013 at 05:01

Nó làm được điều đó vì input.nextInt();không nắm bắt được dòng mới. bạn có thể làm như những người khác đề xuất bằng cách thêm một input.nextLine();bên dưới.
Ngoài ra, bạn có thể thực hiện theo kiểu C # và phân tích cú pháp nextLine thành một số nguyên như sau:

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

Làm điều này cũng hoạt động tốt và nó giúp bạn tiết kiệm một dòng mã.

28 Pshemo Oct 10 2016 at 05:51

TL; DR Sử dụng scanner.skip("\\R")trước mỗi scanner.newLine()cuộc gọi, được thực hiện sau:

  • scanner.next()
  • scanner.next*TYPE*()phương pháp, như scanner.nextInt().

Những điều bạn cần biết:

  • văn bản đại diện cho một vài dòng cũng chứa các ký tự không thể in giữa các dòng (chúng tôi gọi chúng là dấu phân cách dòng) như

  • ký tự xuống dòng (CR - trong chuỗi ký tự được biểu diễn dưới dạng "\r")

  • nguồn cấp dữ liệu dòng (LF - trong chuỗi ký tự được biểu thị bằng "\n")

  • khi bạn đang đọc dữ liệu từ bảng điều khiển, nó cho phép người dùng nhập phản hồi của mình và khi hoàn thành, anh ta cần phải xác nhận bằng cách nào đó sự thật đó. Để làm như vậy, người dùng bắt buộc phải nhấn phím "enter" / "return" trên bàn phím.

Điều quan trọng là phím này bên cạnh việc đảm bảo đặt dữ liệu người dùng vào đầu vào tiêu chuẩn (được đại diện bởi System.innó được đọc bởi Scanner) còn gửi các dấu phân cách dòng phụ thuộc vào hệ điều hành (như đối với Windows \r\n) sau nó.

Vì vậy, khi bạn hỏi người dùng về giá trị như age, và người dùng nhập 42 và nhấn enter, đầu vào chuẩn sẽ chứa "42\r\n".

Vấn đề

Scanner#nextInt(và các phương pháp khác ) không cho phép Máy quét sử dụng các dấu phân cách dòng này. Nó sẽ đọc chúng từ (làm cách nào khác mà Scanner có thể biết rằng không có thêm chữ số nào từ người dùng thể hiện giá trị ngoài việc phải đối mặt với khoảng trắng?) Sẽ xóa chúng khỏi đầu vào tiêu chuẩn, nhưng nó cũng sẽ lưu vào bộ nhớ cache các dấu phân cách dòng đó trong nội bộ . Điều chúng ta cần nhớ là tất cả các phương thức Scanner luôn quét bắt đầu từ văn bản được lưu trong bộ nhớ cache.Scanner#nextTypeSystem.inage

Bây giờ Scanner#nextLine()chỉ cần thu thập và trả về tất cả các ký tự cho đến khi nó tìm thấy dấu phân cách dòng (hoặc cuối luồng). Nhưng vì các dấu phân tách dòng sau khi đọc số từ bảng điều khiển được tìm thấy ngay trong bộ nhớ cache của Máy quét, nó trả về Chuỗi trống, có nghĩa là Máy quét không thể tìm thấy bất kỳ ký tự nào trước các dấu tách dòng đó (hoặc cuối luồng).
BTW nextLinecũng tiêu thụ các bộ tách dòng đó.

Giải pháp

Vì vậy, khi bạn muốn hỏi về số lượng và sau đó cho toàn bộ dòng trong khi tránh rằng chuỗi rỗng như kết quả của nextLine, hoặc

  • tiêu thụ dấu phân cách dòng được để lại nextInttừ bộ nhớ cache của Máy quét
  • gọi nextLine,
  • hoặc IMO, cách dễ đọc hơn sẽ là gọi skip("\\R")hoặc skip("\r\n|\r|\n")để Máy quét bỏ qua phần được khớp bằng dấu phân cách dòng (thông tin thêm về \R: https://stackoverflow.com/a/31060125 )
  • hoàn toàn không sử dụng nextInt(cũng không nexthoặc bất kỳ nextTYPEphương pháp nào ). Thay vào đó, đọc toàn bộ dữ liệu theo từng dòng bằng cách sử dụng nextLinevà phân tích cú pháp số từ mỗi dòng (giả sử một dòng chỉ chứa một số) thành kiểu thích hợp như intvia Integer.parseInt.

BTW : các phương thức có thể bỏ qua dấu phân cách (theo mặc định là tất cả các khoảng trắng như tab, dấu phân cách dòng) bao gồm cả những dấu cách được lưu trong bộ nhớ cache bởi máy quét, cho đến khi chúng tìm thấy giá trị không dấu phân cách tiếp theo (mã thông báo). Nhờ đó cho đầu vào như mãScanner#nextType"42\r\n\r\n321\r\n\r\n\r\nfoobar"

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

sẽ có thể chỉ định đúng num1=42 num2=321 name=foobar.

17 Castaldi Jul 23 2014 at 17:20

Thay vì input.nextLine()sử dụng input.next(), điều đó sẽ giải quyết vấn đề.

Mã sửa đổi:

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

Nếu bạn muốn đọc cả chuỗi và int, giải pháp là sử dụng hai Máy quét:

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

Nếu bạn muốn quét đầu vào nhanh chóng mà không bị nhầm lẫn với phương thức nextLine () của lớp Máy quét, hãy sử dụng Trình quét đầu vào tùy chỉnh cho nó.

Mã:

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

}

Ưu điểm:

  • Đầu vào quét nhanh hơn BufferReader
  • Giảm thời gian phức tạp
  • Đổ bộ đệm cho mỗi lần nhập tiếp theo

Phương pháp:

  • scanChar () - quét một ký tự
  • scanInt () - quét giá trị Integer
  • scanLong () - quét Giá trị dài
  • scanString () - quét giá trị chuỗi
  • scanDouble () - quét Giá trị kép
  • scanInt (int [] array) - quét toàn bộ Mảng (Số nguyên)
  • scanLong (dài [] mảng) - quét hoàn chỉnh Mảng (Dài)

Sử dụng :

  1. Sao chép mã Given bên dưới mã java của bạn.
  2. Khởi tạo đối tượng cho lớp cho trước

ScanReader sc = new ScanReader(System.in); 3. Nhập các Lớp cần thiết:

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. Ném IOException khỏi phương thức chính của bạn để xử lý Exception 5. Sử dụng các phương thức được cung cấp. 6. Thưởng thức

Thí dụ :

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

Để tránh sự cố, hãy sử dụng nextLine();ngay sau nextInt();đó vì nó giúp xóa bộ đệm. Khi bạn nhấn ENTER, nextInt();không ghi lại dòng mới và do đó, bỏ qua Scannermã sau đó.

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()tốt hơn so với phân tích cú pháp đầu vào. Bởi vì hiệu suất khôn ngoan nó sẽ tốt.

6 TaslimOseni Jan 07 2018 at 17:33

Tôi đoán tôi đến khá muộn trong bữa tiệc ..

Như đã nói trước đây, việc gọi input.nextLine()sau khi nhận được giá trị int sẽ giải quyết được vấn đề của bạn. Lý do tại sao mã của bạn không hoạt động là vì không có gì khác để lưu trữ từ đầu vào của bạn (nơi bạn nhập int) vào string1. Tôi sẽ chỉ làm sáng tỏ hơn một chút về toàn bộ chủ đề.

Hãy coi nextLine () là phương thức kỳ lạ trong số các phương thức nextFoo () trong lớp Máy quét. Hãy lấy một ví dụ nhanh .. Giả sử chúng ta có hai dòng mã giống như những dòng bên dưới:

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

Nếu chúng ta nhập giá trị bên dưới (dưới dạng một dòng đầu vào)

54 234

Giá trị của biến của chúng ta firstNumbersecondNumberbiến lần lượt trở thành 54 và 234. Lý do tại sao điều này hoạt động theo cách này là vì một nguồn cấp dòng mới ( tức là \ n ) KHÔNG được tạo tự động khi phương thức nextInt () nhận các giá trị. Nó chỉ đơn giản là lấy "số nguyên tiếp theo" và tiếp tục. Điều này cũng tương tự đối với phần còn lại của các phương thức nextFoo () ngoại trừ nextLine ().

nextLine () tạo nguồn cấp dòng mới ngay sau khi nhận một giá trị; đây là ý nghĩa của @RohitJain khi nói rằng nguồn cấp dữ liệu dòng mới đã được "tiêu thụ".

Cuối cùng, phương thức next () chỉ đơn giản là lấy Chuỗi gần nhất mà không tạo một dòng mới; điều này làm cho phương pháp này được ưu tiên để lấy các Chuỗi riêng biệt trong cùng một dòng.

Tôi hy vọng điều này sẽ giúp .. Chúc bạn mã hóa vui vẻ!

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

Sử dụng 2 đối tượng máy quét thay vì một

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

nếu tôi mong đợi một đầu vào không trống

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


được sử dụng trong ví dụ trên:

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

Trong một lần sử dụng của tôi, tôi đã gặp tình huống đọc một giá trị chuỗi đứng trước một vài giá trị số nguyên . Tôi đã phải sử dụng " vòng lặp for / while " để đọc các giá trị. Và không có gợi ý nào ở trên hoạt động trong trường hợp này.

Sử dụng input.next()thay vì đã input.nextLine()khắc phục sự cố. Hy vọng điều này có thể hữu ích cho những người đối phó với tình huống tương tự.

4 SandeepKumar Dec 18 2019 at 16:08

Như nextXXX()các phương thức không đọc newline, ngoại trừ nextLine(). Chúng ta có thể bỏ qua newlinebất kỳ non-stringgiá trị nào sau khi đọc ( inttrong trường hợp này) bằng cách sử dụng scanner.skip()như sau:

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

Sử dụng mã này, nó sẽ khắc phục sự cố của bạn.

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

Tại sao không sử dụng một Máy quét mới cho mỗi lần đọc? Như bên dưới. Với cách tiếp cận này, bạn sẽ không đối đầu với vấn đề của mình.

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

Vấn đề là với phương thức input.nextInt () - nó chỉ đọc giá trị int. Vì vậy, khi bạn tiếp tục đọc với input.nextLine (), bạn sẽ nhận được phím Enter "\ n". Vì vậy, để bỏ qua điều này, bạn phải thêm input.nextLine (). Hy vọng điều này sẽ rõ ràng ngay bây giờ.

Hãy thử nó như thế:

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