it-roy-ru.com

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

548
blekione

Это связано с тем, что метод Scanner.nextInt не читает символ новая строка в вводе, созданном нажатием клавиши «Ввод», и поэтому вызов 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();
    
651
Rohit Jain

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

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

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

74
Bohemian

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

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

38
Denis Tulskiy

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

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

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

28
Electric Coffee

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

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

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

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

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

Проблема

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

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

Решение

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

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

BTW: 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=42num2=321name=foobar.

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

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

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

Если вы хотите быстро сканировать ввод, не путаясь с методом класса сканера 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) - сканирует полный массив (целое число)
  • scanLong (long [] 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 из вашего основного метода для обработки Exception 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....
7
NIKUNJ KHOKHAR

Если вы хотите прочитать как строки, так и целые числа, решение состоит в том, чтобы использовать два сканера:

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();
5
André Valenti

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

5
shankar upadhyay

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

Как указывалось ранее, вызов 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)IS NOTавтоматически генерируется, когда метод nextInt () принимает значения. Он просто берет "next int" и идет дальше. То же самое относится и к остальным методам nextFoo (), за исключением nextLine ().

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

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

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

1
Taslim Oseni

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

Scanner input = new Scanner(System.in);
System.out.println("Enter numerical value");    
int option;
Scanner input2 = new Scanner(System.in);
option = input2.nextInt();
0
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);
    }
0
Neeraj Gahlawat