スキャナーが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()され、2番目の行が実行されるため、出力が次のようになることです。

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の知識は他の場所にも適用されます。私は単にスキャナーが好きではありません。
ランチャー2013

回答:


831

それのためScanner.nextIntの方法は読まない改行押すことで、作成した入力中の文字「を入力し、」との呼び出しので、Scanner.nextLineそれを読んだ後リターン改行を

Scanner.nextLineafter Scanner.next()または任意のScanner.nextFooメソッド(nextLineそれ自体を除く)を使用すると、同様の動作が発生します。

回避策:

  • 置くどちらのScanner.nextLineそれぞれの後に電話をScanner.nextIntScanner.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ため、を使用する必要があります。例外については後で学習します。EGの場合:- 。「abc」をintに変換したくないですか?Integer.parseIntNumberFormatExceptionInteger.parseInt("abc")
Rohit Jain

3
@blekione。したがって、上記の場合、コードはその時点で停止し、実行を継続することはできません。例外処理を使用すると、このような種類の条件を処理できます。
Rohit Jain

4
後者はどの程度優れていますか?AFAIK Scanner#nextInt()は、グループのコンマとロケールの接頭辞と接尾辞を許可することにより、正しいintを見つける際の寛大さを高めています。Integer#parseInt()は、数字と小数点のみとオプションの符号を許可します。
モルデチャイ2017年

5
個人的Scanner#hasNextFooには、try-catchの代わりに事前にチェックすることを好みますが、それでも機能します。
MildlyMilquetoast 2017年

1
ParseDoubleを使用すると新しい問題が発生し、nextDoubleは10進数の地域構成(。または、)を使用しますが、Parsedoubleは常にUS 10進数(。)を受け取ります。
olmerg 2017年

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

ummは、スキップされた行を使用しないという解決策のようですが、nextLineこの動作の説明が必要です
Eng.Fouad


質問:2012年10月27日16:37に質問。作成14 8月。112011-11-14 12:24。これはどうして可能ですか?
Apoorv Patne

79

これは、数値を入力してを押すEnterinput.nextInt()、「行末」ではなく、数値のみを消費するためです。ときにinput.nextLine()実行する、それが最初の入力からバッファ内に依然として「行の末尾」を消費します。

代わりに、input.nextLine()直後に使用input.nextInt()


7
@Victorバグではありません。指定どおりに機能しています。ただし、ターゲット入力に続いて空白も消費するようにAPIに指示する簡単な方法があるはずだと主張することもできます。
ボヘミアン

そうですか。@Bohemianに感謝します。まさに私が主張していることです。これは変更する必要があると思います。おそらく、次のJCPでこの「問題」を提案する場所を教えていただけますか。
ビクター

@victor [ バグ報告]または[機能のリクエスト]ページから、機能をリクエスト(およびコードを提供する方法を見つける)できます。
ボヘミアン


48

に関するこの問題については、多くの質問があるようですjava.util.Scanner。より読みやすく/慣用的な解決策は、を呼び出しscanner.skip("[\r\n]+")た後に改行文字を削除することnextInt()です。

編集:@PatrickParkerが以下に示すように、ユーザーが数値の後に空白を入力すると、無限ループが発生します。スキップで使用するより良いパターンについては、回答を参照してくださいhttps : //stackoverflow.com/a/42471816/143585



私はバッファ内のデータを削除するために何をすべきか知っていますが、この場合、これで私を助けてください:stackoverflow.com/questions/33585314/having-issues-with-scanner
Khuong

1
参考までに、これはユーザーが数値入力の後にタブまたはスペースを入力すると無限ループを引き起こします。より良いスキップについては、ここで私の回答を参照してください:stackoverflow.com/a/42471816/7098259
Patrick Parker

@PatrickParker:それは確かに無限ループを引き起こします!ありがとうございます。あなたの回答にリンクするように回答を編集しました。
Denis Tulskiy 2017

33

input.nextInt();改行をキャプチャしないので、それが行われます。あなたはinput.nextLine();下に追加することで提案された他の人のようにすることができます。
または、C#スタイルで次のようにnextLineを整数に解析することもできます。

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

これを行うことも同様に機能し、コードの行を節約します。



1
ここでtry catchを使用する必要があります。入力が数値でない場合はどうなりますか。ここでNumberFormatExceptionを処理する必要があります。
Arundev

これは、これを試す各行に1つのintトークンしかないことを前提としています。
cellepo

25

TL; DR次の後に実行されるscanner.skip("\\R")scanner.newLine()呼び出しの前に使用します。

  • scanner.next()
  • scanner.next*TYPE*() 方法。

知っておくべきこと:

  • 数行を表すテキストには、次のように、行の間に印刷できない文字(行区切り文字と呼びます)も含まれています

    • 復帰(CR-で表される文字列リテラル"\r"
    • 改行(LF-で表される文字列リテラル"\n"
  • コンソールからデータを読み取っているときは、ユーザーが応答を入力できます。完了したら、なんとかしてその事実を確認する必要があります。そのためには、ユーザーはキーボードの「Enter」/「Return」キーを押す必要があります。

    重要なのは、ユーザーデータを標準入力(によってSystem.in読み取られるScanner)に配置することを保証するほかに、このキーは\r\nその後にOS依存の行区切り文字(Windowsの場合など)も送信することです。

    したがって、ユーザーにのような値を要求し、ユーザーがage42と入力してEnterキーを押すと、標準入力にはが含まれます"42\r\n"

問題

Scanner#nextInt(および他の方法)スキャナがすることはできません消費これらの行区切りを。それはからそれらを読み込みます(表現し、ユーザからのこれ以上の数字があることを知っているだろうか他のスキャナ標準入力から削除されますどの空白が直面しているよりも値が?)、しかし、それはまたしますキャッシュし、内部でこれらの行区切りを。私たちが覚えておく必要があるのは、すべてのScannerメソッドが常にキャッシュされたテキストからスキャンを開始していることです。 Scanner#nextTypeSystem.inage

今すぐScanner#nextLine()簡単に収集し、すべての文字を返し、それが行区切りが見つかるまで(またはストリームの終わりを)。ただし、コンソールから数値を読み取った後の行区切り文字はスキャナーのキャッシュですぐに検出されるため、空の文字列が返されます。つまり、スキャナーはこれらの行区切り文字(またはストリームの終わり)の前に文字を見つけることができませんでした。
ところでこれらの行セパレーターnextLine消費します。

解決

したがって、の結果としてその空の文字列を回避しながら、番号を要求してから行全体を要求する場合はnextLine

  • nextIntスキャナーキャッシュから残された行区切りを使用
    • 呼び出しnextLine
    • またはIMO より読みやすい方法は、を呼び出すskip("\\R")skip("\r\n|\r|\n")、行区切り文字に一致する部分をスキャナーにスキップさせることです(詳細\Rhttps : //stackoverflow.com/a/31060125
  • nextInt(またはnext、または任意のnextTYPEメソッド)をまったく使用しないでください。代わりに、データnextLineを1行ずつ読み取り、各行の数値を解析して(1行に1つの数値しかないと想定)、intviaのような適切なタイプに変換しInteger.parseIntます。

ところで:メソッドはできるスキップ、彼らが次の非区切り値(トークン)を見つけるまでは、(デフォルトでは、タブ、行区切りのように、すべての空白文字)スキャナによってキャッシュされたものを含むが、区切り文字を。コードのような入力をありがとう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

文字列と整数の両方を読み取りたい場合の解決策は、2つのスキャナーを使用することです。

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()は動作するはずです。
アンドレ・ヴァレンティ

11

Scannerクラスの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()-Long値をスキャンする
  • scanString()-文字列値をスキャンする
  • scanDouble()-Double値をスキャンする
  • scanInt(int [] array)-完全なArray(Integer)をスキャンします
  • scanLong(long [] array)-完全なArray(Long)をスキャンします

使用法 :

  1. Javaコードの下に所定のコードをコピーします。
  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


5

私はパーティーにかなり遅れていると思います。

前述のように、input.nextLine()int値を取得した後に呼び出すと問題が解決します。コードが機能しなかった理由は、入力(intを入力した場所)からに保存するものが他にないためですstring1。トピック全体に少しだけ光を当てます。

ScannerクラスのnextFoo()メソッドの中で奇妙なものとしてnextLine()を検討してください。簡単な例を見てみましょう。次のような2行のコードがあるとします。

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

以下の値を(1行の入力として)入力した場合

54 234

our firstNumbersecondNumbervariable の値はそれぞれ54と234になります。新しいラインフィード(ので、これはこのように動作理由は、すなわち\ nはれていません nextInt()メソッドは値をとるときに自動的に生成します。それは単に「次の整数」を取り、次に進みます。これは、nextLine()を除いて、残りのnextFoo()メソッドでも同じです。

nextLine()は、値を受け取った直後に新しい改行を生成します。これは、@ RohitJainが新しいラインフィードが「消費された」と言うことで意味します。

最後に、next()メソッドは、新しい行生成せずに最も近い文字列を取得するだけです。これにより、これは、同じ単一行内で個別の文字列を取得するための優先的な方法になります。

これが役に立てば幸いです。


「改行」とは?
アーチャー

@Abcd新しいラインフィードは、基本的に「新しいラインから開始する」ことを意味します。
Taslim Oseni

1
その「54 234」の例は本当に物事を明確にします。
アロンソデルアルテ

3

1つではなく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 2017

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

私のユースケースの1つで、いくつかの整数値が前に付い文字列値を読み取るシナリオがありました。値を読み取るには、「for / whileループ」を使用する必要がありました。この場合、上記の提案はどれも機能しませんでした。

問題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()な方法読んでいないnewline除きますnextLine()。次のように使用してnewlinenon-string値を読み取った後(intこの場合)をスキップできscanner.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 2015年

1
スキャナーがメソッドにラップされている場合、GCはそれを処理しませんか?Like:String getInput(){return new Scanner(System.in).nextLine()};
トビアスヨハンソン

これは絶対に誤りです。 nextInt()「新しい」Scannerか、すでに使用されているかに関係なく、改行を消費しません。
Dawood ibnカリーム2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.