web-dev-qa-db-ja.com

Next()またはnextFoo()を使用した後、スキャナがnextLine()をスキップしていませんか。

私は入力を読むために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()がスキップされ、2番目の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()の両方が必要に応じて実行されます。

575
blekione

これは、 Scanner.nextInt メソッドが「Enter」を押して作成された入力内のnewline文字を読み取らないため、 Scanner.nextLineの呼び出しが は、newlineを読み取った後に戻ります。

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

回避策:

  • Scanner.nextLineまたはScanner.nextIntの後にScanner.nextFoo呼び出しを配置し​​て、newlineを含むその行の残りを消費する

    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();
    
717
Rohit Jain

問題は 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();
184
Prine

それはあなたが数を入力するとき、それから押すからです Enterinput.nextInt()は数字だけを消費し、 "行末"は消費しません。 input.nextLine()が実行されると、最初の入力からまだバッファ内にある「行末」を消費します。

代わりに、input.nextLine()の直後にinput.nextInt()を使用してください。

74
Bohemian

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

編集:@PatrickParkerが後述するように、これはユーザーが数の後に空白を入力すると無限ループを引き起こします。 skipと一緒に使うより良いパターンについては彼らの答えを見てください: https://stackoverflow.com/a/42471816/143585

39
Denis Tulskiy

input.nextInt();が改行を捕らえていないからです。下にinput.nextLine();を追加することで他の人が提案したようにすることができます。
あるいは、C#スタイルにしてnextLineを次のように整数に解析することもできます。

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

これを実行しても同様に機能し、コード行を節約できます。

29
Electric Coffee

知っておくべきこと:

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

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

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

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

問題

Scanner#nextInt(およびその他のScanner#nextTypeメソッド)では、スキャナーでconsumeこれらの行区切り文字を使用できません。標準入力から削除するSystem.in(スキャナがage値を表すユーザーからの数字が空白に直面するよりも多くないことをどのように知るか)から読み取りますが、また、cacheこれらの行区切り文字を内部的にします。覚えておく必要があるのは、すべてのScannerメソッドが常にキャッシュされたテキストからスキャンすることです。

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

溶液

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

  • でスキャナーキャッシュからnextIntによって残された行区切り文字を消費します
    • nextLineを呼び出し、
    • またはskip("\\R")を呼び出して、スキャナが行区切りを表す\Rに一致する部分をスキップできるようにします(\Rの詳細: https://stackoverflow.com/a/31060125
  • nextInt(またはnext、またはnextTYPEメソッドも使用しないでください。代わりに、nextLineを使用してデータ全体を行ごとに読み取り、各行の数値を解析して(1行に1つの数値のみが含まれる場合)、Integer.parseIntを介してintのような適切な型に変換します。

BTWScanner#nextTypeメソッドはskipデリミタ(デフォルトではタブ、行セパレータなどのすべての空白)を含む次の区切り文字以外の値(トークン)が見つかるまで、スキャナーによってキャッシュされます。 "42\r\n\r\n321\r\n\r\n\r\nfoobar"コードのような入力のおかげで

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

num1=42num2=321name=foobarを適切に割り当てることができます。

22
Pshemo

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

この問題を回避するには、バッファをクリアするのに役立つので、nextLine();の直後にnextInt();を使用してください。 ENTERを押すと、nextInt();は改行をキャプチャしないため、後でScannerコードをスキップします。

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

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よりも高速に入力をスキャン
  • 時間の複雑さを軽減
  • 次の入力ごとにBufferをフラッシュします

方法:

  • scanChar() - 1文字をスキャンする
  • scanInt() - 整数値をスキャンする
  • scanLong() - Long値をスキャンする
  • scanString() - 文字列値をスキャンする
  • scanDouble() - Double値をスキャンする
  • scanInt(int [] array) - 完全な配列をスキャンする(整数)
  • 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. Provided Methodsを使用します。 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....
8
NIKUNJ KHOKHAR

文字列と整数の両方を読みたい場合、解決策は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();
7
André Valenti

sc.nextLine()は、入力を解析するよりも優れています。性能面では賢明でしょう。

6

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

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

Scannerクラスの nextFoo() メソッドのうち、 nextLine() を奇数として考えます。簡単な例を見てみましょう。以下のような2行のコードがあるとしましょう。

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

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

54 234

firstNumbersecondNumber変数の値はそれぞれ54と234になります。これがこのように機能するのは、nextInt( すなわち\ n IS NOT が自動的に生成されるからです。 )メソッドは値を取り込みます。それは単に "next int" をとって先へ進む。これは、nextLine()以外の他のnextFoo()メソッドと同じです。

nextLine()は値を取った直後に改行を生成します。これは@RohitJainが改行が「消費される」と言うことによって意味するものです。

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

これが役に立つことを願っています..メリーコーディング!

2
Taslim Oseni

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();
1
Harsh Shah
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);
    }
1
Neeraj Gahlawat