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()
がスキップ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()
、私は彼らがなりたいように実行されています。
回答
それのためScanner.nextInt
の方法は読まない改行押すことで、作成した入力中の文字「を入力し、」との呼び出しので、Scanner.nextLine
それを読んだ後リターン改行を。
Scanner.nextLine
afterScanner.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();
問題は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();
これは、数字を入力してからを押すEnterとinput.nextInt()
、「行末」ではなく、数字のみが消費されるためです。ときにinput.nextLine()
実行する、それが最初の入力からバッファ内に依然として「行の末尾」を消費します。
代わりに、input.nextLine()
直後に使用してくださいinput.nextInt()
でこの問題について多くの質問があるようですjava.util.Scanner
。より読みやすく慣用的な解決策は、を呼び出しscanner.skip("[\r\n]+")
た後に改行文字を削除するために呼び出すことだと思いますnextInt()
。
編集:以下で説明する@PatrickParkerのように、ユーザーが数字の後に空白を入力すると、無限ループが発生します。スキップで使用するより良いパターンについては、彼らの回答を参照してください:https://stackoverflow.com/a/42471816/143585
input.nextInt();
改行をキャプチャしないため、これを行います。input.nextLine();
下に追加することで、他の提案と同じように行うことができます。
または、C#スタイルで実行し、nextLineを次のように整数に解析することもできます。
int number = Integer.parseInt(input.nextLine());
これを行うことも同様に機能し、コード行を節約できます。
TL; DRscanner.skip("\\R")
各scanner.newLine()
呼び出しの前に使用します。これは次の後に実行されます。
scanner.next()
scanner.next*TYPE*()
のようなメソッドscanner.nextInt()
。
あなたが知る必要があること:
数行を表すテキストには、次のように行間に印刷できない文字(行区切り文字と呼びます)も含まれます。
キャリッジリターン(CR-として表される文字列リテラル内
"\r"
)改行(LF-として表される文字列リテラル内
"\n"
)コンソールからデータを読み取るとき、ユーザーは応答を入力できます。完了したら、何らかの方法でその事実を確認する必要があります。これを行うには、ユーザーはキーボードの「Enter」/「Return」キーを押す必要があります。
重要なのは、ユーザーデータを標準入力(によってSystem.in
読み取られるScanner
)に配置することを保証することに加えて、このキーは、\r\n
その後にOSに依存する行区切り記号(Windowsの場合など)も送信することです。
したがって、のような値をユーザーに要求し、ユーザーがage
42と入力してEnterキーを押すと、標準入力にはが含まれます"42\r\n"
。
問題
Scanner#nextInt
(および他の方法)スキャナがすることはできません消費これらの行区切りを。それはからそれらを読み込みます(表現し、ユーザからのこれ以上の数字があることを知っているだろうか他のスキャナ標準入力から削除されますどの空白が直面しているよりも値が?)、しかし、それはまたしますキャッシュし、内部でこれらの行区切りを。覚えておく必要があるのは、すべてのScannerメソッドは常にキャッシュされたテキストからスキャンしているということです。Scanner#nextType
System.in
age
これでScanner#nextLine()
、行区切り文字(またはストリームの終わり)が見つかるまで、すべての文字を収集して返すだけです。ただし、コンソールから数値を読み取った後の行区切り文字はScannerのキャッシュですぐに見つかるため、空の文字列が返されます。つまり、Scannerはこれらの行区切り記号(またはストリームの終わり)の前の文字を見つけることができませんでした。
ところで、これらの行区切り文字nextLine
も使用します。
解決
したがって、の結果としてその空の文字列を避けながら、番号を要求してから行全体を要求する場合はnextLine
、
nextInt
スキャナーキャッシュから残された行区切り文字を消費する- 呼び出し
nextLine
、 - またはIMOのより読みやすい方法は、を呼び出す
skip("\\R")
かskip("\r\n|\r|\n")
、スキャナーに行区切り文字と一致する部分をスキップさせることです(詳細\R
:https://stackoverflow.com/a/31060125) nextInt
(またはnext
、または任意のnextTYPE
メソッド)をまったく使用しないでください。代わりに、を使用してデータ全体nextLine
を1行ずつ読み取り、各行の数値を解析して(1行に1つの数値しか含まれていないと想定)、int
viaのように適切なタイプにし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
。
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();
}
文字列とintの両方を読み取りたい場合、解決策は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();
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()-1文字をスキャンします
- scanInt()-整数値をスキャンします
- scanLong()-Long値をスキャンします
- scanString()-文字列値をスキャンします
- scanDouble()-Double値をスキャンします
- scanInt(int [] array)-完全なArray(Integer)をスキャンします
- scanLong(long [] array)-完全なArray(Long)をスキャンします
使用法 :
- 指定されたコードをJavaコードの下にコピーします。
- 指定されたクラスのオブジェクトを初期化します
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....
この問題を回避するには、バッファをクリアするのに役立つため、nextLine();
直後に使用してくださいnextInt();
。を押すとENTER
、nextInt();
改行がキャプチャされないため、Scanner
後でコードをスキップします。
Scanner scanner = new Scanner(System.in);
int option = scanner.nextInt();
scanner.nextLine(); //clearing the buffer
sc.nextLine()
入力を解析するよりも優れています。パフォーマンス的には良いでしょうから。
私はパーティーにかなり遅れていると思います。
前に述べinput.nextLine()
たように、int値を取得した後に呼び出すと、問題が解決します。コードが機能しなかった理由は、入力(intを入力した場所)からに格納するものが他になかったためですstring1
。トピック全体にもう少し光を当てます。
nextLine()は、ScannerクラスのnextFoo()メソッドの中で奇妙なものと考えてください。簡単な例を見てみましょう。次のような2行のコードがあるとします。
int firstNumber = input.nextInt();
int secondNumber = input.nextInt();
以下の値を(1行の入力として)入力した場合
54 234
ourfirstNumber
とsecondNumber
variableの値はそれぞれ54と234になります。新しいラインフィード(ので、これはこのように動作理由は、すなわち\ nは) れていませんnextInt()メソッドは値をとるときに自動的に生成します。それは単に「次のint」を取り、次に進みます。これは、nextLine()を除く残りのnextFoo()メソッドでも同じです。
nextLine()は、値を取得した直後に新しい改行を生成します。これは、@ RohitJainが、改行が「消費された」と言うことを意味します。
最後に、next()メソッドは、改行を生成せずに最も近い文字列を取得します。これにより、これは同じ1行内で別々の文字列を取得するための優先的な方法になります。
これがお役に立てば幸いです。メリーコーディング!
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つではなく2つのスキャナーオブジェクトを使用する
Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();
空でない入力を期待する場合
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
私のユースケースの1つでは、2つの整数値が前に付いた文字列値を読み取るシナリオがありました。値を読み取るには、「for / whileループ」を使用する必要がありました。そして、上記の提案はどれもこの場合はうまくいきませんでした。
問題input.next()
をinput.nextLine()
修正する代わりに使用する。これが同様のシナリオを扱っている人たちに役立つことを願っています。
以下のようnextXXX()
な方法読んでいないnewline
除きますnextLine()
。以下のように使用することで、newline
任意のnon-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);
このコードを使用すると、問題が修正されます。
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)
すべての読み取りに新しいスキャナーを使用してみませんか?以下のように。このアプローチでは、問題に直面することはありません。
int i = new Scanner(System.in).nextInt();
問題は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();