next () 또는 nextFoo ()를 사용한 후 스캐너가 nextLine ()을 건너 뛰고 있습니까?


684

내가 사용하고 Scanner방법 nextInt()과 nextLine()입력을 읽는.

다음과 같이 보입니다 :

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)

문제는 숫자 값을 입력 한 후 첫 번째 값을 input.nextLine()건너 뛰고 두 번째 input.nextLine()값을 실행하여 출력이 다음과 같이 표시된다는 것입니다.

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

내 응용 프로그램을 테스트했는데 문제가을 사용하는 것처럼 보입니다 input.nextInt(). 내가 그것을 삭제하면, 모두 string1 = input.nextLine()와 string2 = input.nextLine()내가 그들이 원하는대로 실행됩니다.


5
또는 당신은 나와 같이 BufferedReader를 사용할 수 있습니다 :) 나는 그것이 오래된 학교인지 상관하지 않으며, 항상 효과가 있었고 항상 나를 위해 일할 것입니다. 또한 BufferedReader에 대한 지식은 다른 곳에 적용됩니다. 나는 단순히 스캐너를 좋아하지 않습니다.
— Cruncher

답변:


831

Scanner.nextInt메소드가 "Enter"키를 눌러 작성된 입력에서 개행 문자를 읽지 않기 때문에 Scanner.nextLine해당 개행 을 읽은 후 리턴 이 호출되기 때문 입니다.

Scanner.nextLine이후 Scanner.next()또는 다른 Scanner.nextFoo방법 ( nextLine자체 제외 ) 을 사용할 때 비슷한 동작이 발생합니다 .

해결 방법 :

  • 중 하나 넣어 Scanner.nextLine각 한 후 전화를 Scanner.nextInt하거나 Scanner.nextFoo그 라인을 포함한 나머지 소비를 줄 바꿈

    int option = input.nextInt();
    input.nextLine();  // Consume newline left-over
    String str1 = input.nextLine();
    
  • 또는 더 나은 방법으로 입력을 읽고 Scanner.nextLine입력을 필요한 형식으로 변환하십시오. 예를 들어, Integer.parseInt(String)방법을 사용하여 정수로 변환 할 수 있습니다 .

    int option = 0;
    try {
        option = Integer.parseInt(input.nextLine());
    } catch (NumberFormatException e) {
        e.printStackTrace();
    }
    String str1 = input.nextLine();
    

4
@blekione. 당신은 사용할 필요가 try-catch있기 때문에 Integer.parseInt발생합니다 NumberFormatException잘못된 인수가 전달 된 경우. 나중에 예외에 대해 배울 것입니다. EG의 경우 :- Integer.parseInt("abc"). "abc"가 int로 변환되는 것을 원하지 않습니까?
— Rohit Jain

3
@blekione. 따라서 위의 경우 해당 시점에서 코드가 중지되고 계속 실행할 수 없습니다. 예외 처리를 사용하면 이러한 종류의 조건을 처리 할 수 ​​있습니다.
— Rohit Jain

4
후자는 어느 정도 더 낫습니까? AFAIK Scanner # nextInt ()는 그룹 쉼표와 로캘 접두사 및 접미사를 허용하여 올바른 정수를 찾는 데 훨씬 관대합니다. Integer # parseInt ()는 숫자와 소수점 및 옵션 부호 만 허용합니다.
— Mordechai

5
나는 개인적 Scanner#hasNextFoo으로 try-catch 대신 미리 검사를 선호 하지만 그도 효과가 있습니다.
— MildlyMilquetoast

1
ParseDouble 사용에 새로운 문제가 있습니다. nextDouble은 소수 (. 또는)의 지역 구성을 사용하지만 Parsedouble은 항상 미국 10 진수 (.)를받습니다.
— olmerg

209

문제는 input.nextInt () 메소드에 있습니다. int 값만 읽습니다. 따라서 input.nextLine ()을 계속 사용하면 "\ n"Enter 키가 나타납니다. 따라서 이것을 건너 뛰려면 input.nextLine () 을 추가해야합니다 . 이것이 분명해지기를 바랍니다.

그렇게 해보십시오.

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

음 스킵 라인이 아닌 사용하고, 해결책을 것 같다 nextLine,하지만, 난 여전히이 문제에 대한 설명이 필요
— Eng.Fouad


질문 : 16:27에 10 월 27 '12을 물었다. 생성 14 aug. 112011-08-14 12:24. 이것이 어떻게 가능합니까?
— Apoorv Patne

79

당신이 다음을 눌러 숫자를 입력 할 때 때문입니다 Enter, input.nextInt()수만이 아니라 "줄의 끝을"소비한다. input.nextLine()실행될 때 첫 번째 입력에서 여전히 버퍼에있는 "end of line"을 사용합니다.

대신에 input.nextLine()바로 사용 하십시오input.nextInt()


7
@ 빅터 그것은 버그가 아닙니다. 지정된대로 작동합니다. API에 대상 입력 다음에 공백을 사용하도록 지시하는 쉬운 방법이 있어야한다고 주장 할 수 있습니다.
— 보헤미안

내가 참조. @Bohemian에게 감사드립니다. 나는 이것이 변경되어야한다고 생각한다. 아마도 다음 JCP에서이 "문제"를 제안 할 수있는 곳을 알려줄 수있을 것이다.
— Victor

@victor 버그 신고 또는 기능 요청 페이지를 통해 기능을 요청하고 코드를 제공하는 방법을 찾을 수 있습니다 .
— 보헤미안


48

이 문제와 관련하여 많은 질문이있는 것 같습니다 java.util.Scanner. 더 읽기 쉽고 관용적 인 해결책은 전화 scanner.skip("[\r\n]+")한 후 개행 문자를 삭제 하기 위해 전화 하는 것 nextInt()입니다.

편집 : @PatrickParker가 아래에 언급했듯이 사용자가 숫자 뒤에 공백을 입력하면 무한 루프가 발생합니다. skip과 함께 사용하기에 더 나은 패턴에 대한 답변을 보려면 https://stackoverflow.com/a/42471816/143585



나는 우리가 버퍼의 데이터를 제거하기 위해 무엇을 알고 있지만,이 경우는, 이것 좀 도와주세요 : stackoverflow.com/questions/33585314/having-issues-with-scanner
— Khuong

1
참고로, 사용자가 숫자 입력 후 탭이나 공백을 입력하면 무한 루프가 발생합니다. 여기 내 대답을 참조하십시오 더 나은 건너 뜁니다 stackoverflow.com/a/42471816/7098259
— 패트릭 파커

@ 패트릭 파커 : 그것은 실제로 무한 루프를 유발합니다! 감사합니다. 귀하의 답변을 수정했습니다.
— Denis Tulskiy

33

input.nextInt();개행을 캡처하지 않기 때문에 그렇게합니다. input.nextLine();아래 에 추가하여 제안 된 다른 사람들처럼 할 수 있습니다.
또는 C # 스타일로 nextLine을 정수로 구문 분석 할 수 있습니다.

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

이 작업을 수행해도 코드가 줄어 듭니다.



1
여기서 catch catch를 사용해야합니다. 입력 값이 숫자가 아닌 경우 어떻게됩니까? 여기서 NumberFormatException을 처리해야합니다.
— Arundev

이것은 당신이 이것을 시도하는 각 줄에 하나의 int 토큰 만 있다고 가정합니다.
— cellepo

25

TL; DR scanner.skip("\\R")각 scanner.newLine()호출 전에 사용 하며 다음 후에 실행됩니다.

  • scanner.next()
  • scanner.next*TYPE*() 방법.

알아야 할 사항 :

  • 몇 줄을 나타내는 텍스트에는 줄 사이에 인쇄 할 수없는 문자도 포함됩니다 (우리는 줄 구분 기호라고 부릅니다)

    • 캐리지 리턴 (으로 표시되는 문자열 리터럴에서 CR- "\r")
    • 줄 바꿈 (LF-로 표시되는 문자열 리터럴 "\n")
  • 콘솔에서 데이터를 읽을 때, 그것은 자신의 응답을 입력 할 수있는 사용자를 허용하고 그는이 완료되면 그가 할 필요가 어떻게 든 그 사실을 확인합니다. 그렇게하려면, 사용자는 키보드에서 "enter"/ "return"키를 눌러야합니다.

    중요한 것은 사용자 데이터를 표준 입력 (로 표시되는 System.in것으로 표시)에 배치하는 것 외에도이 키 Scanner는 OS 종속 행 구분 기호 (Windows와 같은)를 전송 \r\n합니다.

    따라서 사용자에게와 같은 값을 요구할 때 age사용자 유형 42와 Enter 키를 누르면 표준 입력에 포함 "42\r\n"됩니다.

문제

Scanner#nextInt(및 기타 방법)에서는 스캐너가 이러한 행 구분 기호 를 사용할 수 없습니다 . 그것은에서 읽을 것이다 (대표 사용자로부터 더 이상 자리가 있다는 것을 알고 얼마나 다른 스캐너 표준 입력에서 제거 할 공백에 직면 이상의 값?), 그러나 그것은 또한 것이다 캐시 내부적으로 그 라인 분리를 . 우리가 기억해야 할 것은 모든 스캐너 메소드가 항상 캐시 된 텍스트부터 스캔한다는 것입니다. Scanner#nextTypeSystem.inage

이제 줄 구분 기호 (또는 스트림 끝)를 찾을 때까지Scanner#nextLine() 모든 문자를 수집하고 반환합니다 . 그러나 콘솔에서 숫자를 읽은 후 줄 구분 기호는 스캐너의 캐시에서 즉시 발견되므로 빈 문자열을 반환합니다. 즉, 줄 구분 기호 (또는 스트림 끝) 앞에 스캐너가 문자를 찾을 수 없습니다. BTW 또한 소비 하는 라인 분리합니다.
nextLine

해결책

그래서 당신의 결과로 그 빈 문자열을 피하면서 전체 라인 다음 번호를 요청하고 싶을 때 nextLine중,

  • nextInt스캐너 캐시에서 남은 줄 구분 기호 를
    • 전화 nextLine,
    • 또는 IMO 더 읽기 쉬운 방법은 호출 skip("\\R")하거나 skip("\r\n|\r|\n")스캐너가 줄 구분 기호와 일치하는 부분을 건너 뛰도록 하는 것입니다 (자세한 정보 \R: https : //.com/a/31060125 )
  • nextInt( next또는 다른 nextTYPE방법)을 전혀 사용하지 마십시오 . 대신 nextLine각 행의 번호를 사용하여 한 줄씩 전체 데이터를 읽고 (한 줄에 하나의 숫자 만 있다고 가정) intvia 와 같은 적절한 유형으로 구문 분석하십시오 Integer.parseInt.

BTW : 메소드는 다음에 구분되지 않는 값 (토큰)을 찾을 때까지 스캐너에 의해 캐시 된 것을 포함하여 구분 기호 (기본적으로 탭, 줄 구분 기호와 같은 모든 공백)를 건너 뛸 수 있습니다 . 코드 와 같은 입력을위한 덕분입니다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();

제대로 할당 할 수 있습니다 num1=42 num2=321 name=foobar.


14

대신에 input.nextLine()사용 input.next(), 그 문제를 해결해야한다.

수정 된 코드 :

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


13

문자열과 정수를 모두 읽으려면 두 개의 스캐너를 사용하는 것이 좋습니다.

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

1
이것은 내가 한동안 지금 찾고 있었던 것입니다. 똑똑한 움직임!
— Liam Wilson

1
@BdLearner scanner.nextLine()가 작동해야합니다.
— André Valenti

11

스캐너 클래스 nextLine () 메소드에 혼동하지 않고 입력을 빠르게 스캔하려면 사용자 정의 입력 스캐너를 사용하십시오.

코드 :

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

}

장점 :

  • BufferReader보다 빠른 입력 검색
  • 시간 복잡성을 줄입니다
  • 다음 입력마다 플러시 버퍼

방법 :

  • scanChar ()-단일 문자 스캔
  • scanInt ()-스캔 정수 값
  • scanLong ()-긴 값 스캔
  • scanString ()-스캔 문자열 값
  • scanDouble ()-스캔 더블 값
  • scanInt (int [] array)-완전한 Array (Integer)를 스캔합니다
  • scanLong (long [] array)-완전한 Array (Long)을 스캔합니다

사용법 :

  1. 자바 코드 아래에 주어진 코드를 복사하십시오.
  2. 주어진 클래스에 대한 객체 초기화

ScanReader sc = new ScanReader(System.in); 3. 필요한 수업 가져 오기 :

import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; 4. 메인 메소드에서 IOException을 던져 예외를 처리합니다. 5. 제공된 메소드를 사용하십시오. 6. 즐기십시오

예 :

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

10

이 문제를 피 하려면 버퍼를 지우는 데 도움이되므로 nextLine();즉시 사용 하십시오 nextInt();. 당신이 누르면 ENTER는 nextInt();새로운 라인을 캡처하고 따라서 생략하지 않습니다 Scanner나중에 코드를.

Scanner scanner =  new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer

9

sc.nextLine()입력 구문 분석과 비교할 때 더 좋습니다. 성능이 현명하기 때문에 좋습니다.


5

파티에 늦었을 것 같아 ..

앞에서 언급했듯이 input.nextLine()int 값을 얻은 후에 전화 하면 문제가 해결됩니다. 코드가 작동하지 않는 이유는 입력 (int를 입력 한 곳)에 저장할 다른 것이 없기 때문 string1입니다. 나는 전체 주제에 대해 조금 더 밝힐 것이다.

고려 () 꽵를 중 괴상 한 개로서 nextFoo () 스캐너 클래스 방법. 간단한 예를 들어 보자. 아래 코드와 같이 두 줄의 코드가 있다고 가정 해 봅시다.

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

아래의 값을 입력하면 (한 줄의 입력으로)

54234

our firstNumber와 secondNumbervariable 의 값은 각각 54와 234가됩니다. 이런 방식으로 작동하는 이유 는 nextInt () 메소드가 값을 취할 때 새 줄 바꿈 ( 예 : \ n )이 자동으로 생성 되지 않기 때문 입니다. 단순히 "다음 int" 를 가져 와서 계속 진행합니다. 이것은 nextLine ()을 제외한 나머지 nextFoo () 메소드와 동일합니다.

nextLine ()은 값을 얻은 직후 새 줄 바꿈을 생성합니다. 이것은 @RohitJain이 새로운 줄 바꿈이 "소비되었다"는 것을 의미합니다.

마지막으로 next () 메소드 는 새로운 줄 을 생성 하지 않고 가장 가까운 문자열 을 가져옵니다 . 이것은 동일한 단일 행 내에서 별도의 문자열을 취하는 기본 방법입니다.

도움이 되길 바랍니다 .. 즐거운 코딩!


"새 줄 바꿈"이란 무엇입니까?
— Archer

@Abcd 줄 바꿈은 기본적으로 '새 줄에서 시작'을 의미합니다.
— Taslim Oseni

1
그 "54 234"예제는 사실을 명확히합니다.
— Alonso del Arte

3

하나 대신 2 개의 스캐너 개체를 사용하십시오.

Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");    
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();

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

nextInt () 메소드 바로 다음에 nextLine () 메소드를 사용하는 경우 nextInt ()는 정수 토큰을 읽습니다. 이 때문에 해당 정수 입력 행의 마지막 개행 문자는 여전히 입력 버퍼에 대기하고 다음 nextLine ()은 나머지 정수 행 (비어 있음)을 읽습니다.
— Neeraj Gahlawat

2

비어 있지 않은 입력이 예상되는 경우

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


위 예제에서 사용 된

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

2

유스 케이스 중 하나에서 문자열 값 을 읽고 두 개의 정수 값 을 읽는 시나리오가있었습니다 . 값을 읽으려면 " for / while loop " 를 사용해야했습니다 . 그리고이 경우 위의 제안 중 어느 것도 효과가 없었습니다.

문제를 해결하는 input.next()대신 사용 input.nextLine(). 이것이 비슷한 시나리오를 다루는 사람들에게 도움이되기를 바랍니다.


2

이 코드를 사용하면 문제가 해결됩니다.

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)

2

를 제외하고 nextXXX()메소드는 읽지 않습니다 . 다음과 같이 사용하여 값 을 읽은 후 ( 이 경우)를 건너 뛸 수 있습니다.newlinenextLine()newlinenon-stringintscanner.skip()

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

0

독서 할 때마다 새 스캐너를 사용하지 않겠습니까? 아래처럼. 이 방법을 사용하면 문제에 직면하지 않습니다.

int i = new Scanner(System.in).nextInt();

3
그러나 Scanner메모리 누수를 방지하려면를 닫아야합니다 . 시간 낭비?
— TheCoffeeCup

1
스캐너가 분석법으로 포장 된 경우 GC가이를 처리하지 않습니까? 다음과 같습니다 : String getInput () {return new Scanner (System.in) .nextLine ()};
— Tobias Johansson 2016 년

이것은 절대적으로 맞지 않습니다. nextInt()"새" Scanner인지 또는 이미 사용 된 것인지에 관계없이 줄 바꿈을 사용하지 않습니다 .
— Dawood ibn Kareem
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.