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

Ответ 1

Это потому, что метод Scanner.nextInt не читает символ новой строки в вводе, созданном нажатием "Enter", и поэтому вызов Scanner.nextLine возвращается после чтения этой новой строки.

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

Временное решение:

  • Либо поместите вызов Scanner.nextLine после каждого Scanner.nextInt либо Scanner.nextFoo чтобы использовать оставшуюся часть этой строки, включая 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();
    

Ответ 2

Проблема заключается в методе 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();

Ответ 3

Это потому, что, когда вы вводите номер, нажмите Enter, input.nextInt() потребляет только номер, а не "конец строки". Когда input.nextLine() выполняется, он потребляет "конец строки" все еще в буфере от первого входа.

Вместо этого используйте input.nextLine() сразу после input.nextInt()

Ответ 4

Кажется, у этой проблемы много вопросов с java.util.Scanner. Я думаю, что более читаемым/идиоматическим решением было бы вызвать scanner.skip("[\r\n]+"), чтобы удалить любые символы новой строки после вызова nextInt().

ИЗМЕНИТЬ: как заметил @PatrickParker ниже, это приведет к бесконечному циклу, если пользователь вводит пробелы после номера. Посмотрите их ответ на лучший шаблон для использования с пропуском: fooobar.com/questions/281/...

Ответ 5

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

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

Выполнение этого работает так же хорошо, и оно сохраняет строку кода.

Ответ 6

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

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

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

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

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

проблема

Scanner#nextInt (и другие методы Scanner#next Type) не позволяет Scanner использовать эти разделители строк. Он будет читать их из System.in (как еще Сканер узнает, что от пользователя больше нет цифр, представляющих значение age не с пробелом?), Что удалит их из стандартного ввода, но он также кеширует эти разделители строк внутри. Нам нужно помнить, что все методы Scanner всегда сканируют, начиная с кэшированного текста.

Теперь Scanner#nextLine() просто собирает и возвращает все символы, пока не найдет разделители строк (или конец потока). Но поскольку разделители строк после считывания числа с консоли сразу обнаруживаются в кэше сканера, он возвращает пустую строку, то есть сканер не смог найти ни одного символа перед этими разделителями строк (или концом потока).
Кстати, nextLine также использует эти разделители строк.

Решение

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

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

КСТАТИ: Scanner#next Type Методы Scanner#next Type могут пропускать разделители (по умолчанию все пробелы, такие как вкладки, разделители строк), включая те, которые кэшируются сканером, пока они не найдут следующее значение без разделителя (токен). Благодаря этому для ввода как "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.

Ответ 7

Вместо 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();
}

Ответ 8

Если вы хотите прочитать как строки, так и 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();

Ответ 9

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

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

Ответ 10

Если вы хотите быстро сканировать входные данные, не запутавшись в методе nextLine() класса Scanner, используйте для этого специальный пользовательский сканер ввода.

Код:

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
  • Уменьшает сложность времени
  • Буфер Flushes для каждого следующего ввода

Методы:

  • scanChar() - просмотр одиночного символа
  • scanInt() - определение целочисленного значения
  • scanLong() - сканирование Длительное значение
  • scanString() - сканировать значение строки
  • scanDouble() - проверка двойного значения
  • scanInt (int [] array) - сканирует полный массив (целое число)
  • scanLong (long [] array) - сканирует полный массив (длинный)

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

  • Скопируйте данный код под кодом 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....

Ответ 11

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

Ответ 12

Наверное, я очень опаздываю на вечеринку.

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

Рассмотрим nextLine() как нечетный среди методов nextFoo() в классе Scanner. Возьмем быстрый пример. Скажем, у нас есть две строки кода, подобные приведенным ниже:

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

Если ввести значение ниже (в виде одной строки ввода)

54 234

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

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

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

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

Ответ 13

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

Ответ 14

Используйте 2 объекта сканера вместо одного

Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");    
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();

Ответ 15

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

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

Ответ 16

если я ожидаю непустой ввод

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

Ответ 17

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

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