Сканер пропускает nextLine () после использования next () или nextFoo ()?

я использую 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() выполнены, как я хочу, чтобы они быть.

15 ответов


вот так Scanner.nextInt метод не потребляет последние строки характер вашего ввода, и таким образом, что newline потребляется в следующем вызове Scanner.nextLine.

вы столкнетесь с подобным поведением при использовании Scanner.nextLine после Scanner.next() и Scanner.nextFoo способ (кроме nextLine сам.)

решение:

  • либо стрелять холостым 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();
    

проблема заключается в вход.nextInt() метод-он считывает только значение int. Поэтому, когда вы продолжаете читать с input.nextLine () вы получаете клавишу "\n" Enter. Так, чтобы пропустить это, вы должны добавить вход.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().

EDIT :как @ PatrickParker отметил ниже, это вызовет бесконечный цикл, если пользователь вводит любые пробелы после числа. См. их ответ для лучшего шаблона для использования с skip:https://stackoverflow.com/a/42471816/143585


Он делает это, потому что input.nextInt(); не захватывает новую строку. вы можете сделать, как и другие предложенные, добавив input.nextLine(); внизу.
В качестве альтернативы вы можете сделать это в стиле C# и разобрать следующую строку на целое число, например:

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

это работает так же хорошо, и это экономит вам строку кода.


вещи, которые вам нужно знать:

  • текст, который представляет несколько строк, также содержит непечатаемые символы между строками (мы называем их разделителями строк), такие как

    • возврат каретки (CR-в строковых литералах, представленных как "\r")
    • подача строки (LF-в строковых литералах, представленных как "\n")
  • когда вы читаете данные от консоли, оно позволяет потребителю ввести его ответ, и когда он закончит, ему нужно как-то подтвердить этот факт. Для этого пользователю необходимо нажать клавишу "enter"/"return" на клавиатуре.

    важно то, что этот ключ помимо обеспечения размещения пользовательских данных стандартный ввод (в лице System.in, который считывается Scanner) также отправляет зависимые от ОС разделители строк (например, для Windows \r\n) после него.

    поэтому, когда вы спрашиваете у пользователя значение age, и типы пользователей 42 и нажимает enter, стандартный ввод будет содержать "42\r\n".

и потребляет эти разделители строк.

решение

поэтому, когда вы хотите попросить номер, а затем для всей строки, избегая этой пустой строки в результате nextLine, либо

  • потребляйте разделитель строк, оставленный nextInt из кэша сканеров
    • вызов nextLine,
    • или по телефону skip("\R") to пусть сканер пропустит часть, соответствующую \R который представляет разделитель строк (подробнее о \R: https://stackoverflow.com/a/31060125)
  • не используйте nextInt (nor next, или любое nextTYPE методы) вообще. Вместо этого прочитайте всю строку данных, используя nextLine и разбора чисел из каждой строки (если строка содержит только одно число) для соответствующего типа int через Integer.parseInt.

кстати: Scanner#nextType методы пропустить разделители (по умолчанию все пробелы, такие как вкладки, разделители строк), включая кэшированные сканером, пока они не найдут следующее значение без разделителя (токен). Благодаря этому для ввода like "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();
}

чтобы избежать проблемы, используйте nextLine(); сразу после nextInt(); как это помогает в очистке буфера. Когда вы нажимаете ENTER на nextInt(); не захватывает новую строку и, следовательно, пропускает Scanner код позже.

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

если вы хотите быстро сканировать вход, не путаясь в метод класса сканера 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) - сканирование полного массива(Integer)
  • scanLong (Long[] array) - сканирование полного массива (Long)

использование :

  1. скопируйте данный код ниже кода java.
  2. инициализировать объект для данного Класс!--12-->

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

Если вы хотите читать как строки, так и ints, решение заключается в использовании двух сканеров:

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

sc.nextLine() лучше по сравнению с разбором ввода. Потому что производительность мудрая, это будет хорошо.


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

мое тестирование дало те же результаты, что и Prine, однако я подумал о довольно простом обходном пути:

используя BufferedReader#nextLine(), Если бы Scanner#readLine(), избегает этой ошибки. Вы даже можете написать свою собственную оболочку сканера, чтобы переопределить функцию readLine сканера функцией bufferedreader nextLine.


Я думаю, что я довольно поздно на вечеринку..

как уже было сказано, вызываю input.nextLine() после получения значения int решит вашу проблему. Причина, по которой ваш код не работал, заключалась в том, что больше нечего было хранить из вашего ввода (где вы ввели int) в string1. Я просто пролью немного больше света на эту тему.

считают nextLine () как нечетный среди nextFoo() методы в классе сканера. Давайте возьмем небольшой пример.. Предположим, у нас есть две строки кода, как показано ниже:

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

если мы вводим значение ниже (как одну строку ввода)

54 234

ценности firstNumber и secondNumber переменная становится 54 и 234 соответственно. Причина, по которой это работает таким образом, заключается в том, что новый канал Линии (i.e \n) НЕ автоматически генерируется при методе nextInt() принимает значения. Он просто принимает "next int" и движется дальше. Это то же самое для остальных методов nextFoo (), кроме nextLine().

nextLine () генерирует новый канал строки сразу после принятия значения; это то, что @RohitJain означает, говоря, что новый канал строки "потребляется".

наконец, метод next () просто принимает ближайшую строку без создание новой строки; это делает это предпочтительным методом для принятия отдельные строки в одной строке.

надеюсь, это поможет.. Веселого кодирования!


почему бы не использовать новый сканер для каждого чтения? Как внизу. При таком подходе вы не столкнетесь со своей проблемой.

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