Máy quét đang bỏ qua nextLine () sau khi sử dụng next () hoặc nextFoo ()?
Tôi đang sử dụng các Scanner
phương pháp nextInt()
và 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()
và string2 = input.nextLine()
đều được thực thi như tôi muốn.
Trả lời
Đó là bởi vì Scanner.nextInt
phương thức không đọc ký 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.nextLine
trả 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.nextLine
after Scanner.next()
hoặc bất kỳ Scanner.nextFoo
phương thức nào (ngoại trừ nextLine
chính nó).
Cách giải quyết:
Thực hiện
Scanner.nextLine
cuộc gọi sau mỗi cuộc gọiScanner.nextInt
hoặcScanner.nextFoo
sử dụng phần còn lại của dòng đó bao gồm cả dòng mớiint 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.nextLine
và 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ằngInteger.parseInt(String)
phương pháp.int option = 0; try { option = Integer.parseInt(input.nextLine()); } catch (NumberFormatException e) { e.printStackTrace(); } String str1 = input.nextLine();
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();
Đó 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()
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
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ã.
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.in
nó đượ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#nextType
System.in
age
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 nextLine
cũ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
nextInt
từ 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ặcskip("\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ôngnext
hoặc bất kỳnextTYPE
phươ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ụngnextLine
và 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ưint
viaInteger.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
.
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();
}
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();
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 :
- Sao chép mã Given bên dưới mã java của bạn.
- 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....
Để 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 Scanner
mã sau đó.
Scanner scanner = new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
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.
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 firstNumber
và secondNumber
biế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ẻ!
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);
}
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();
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
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ự.
Như nextXXX()
các phương thức không đọc newline
, ngoại trừ nextLine()
. Chúng ta có thể bỏ qua newline
bất kỳ non-string
giá trị nào sau khi đọc ( int
trong 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);
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)
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();
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();