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();. 당신이 누르면 ENTERnextInt();새로운 라인을 캡처하고 따라서 생략하지 않습니다 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 firstNumbersecondNumbervariable 의 값은 각각 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.