«1. Обзор Scanner

В этом кратком руководстве мы покажем, как использовать класс Java Scanner — для чтения ввода, поиска и пропуска шаблонов с разными разделителями.

2. Сканирование файла

Сначала давайте посмотрим, как прочитать файл с помощью сканера.

В следующем примере мы читаем файл, содержащий «Hello world» в токены:

@Test
public void whenReadFileWithScanner_thenCorrect() throws IOException{
    Scanner scanner = new Scanner(new File("test.txt"));

    assertTrue(scanner.hasNext());
    assertEquals("Hello", scanner.next());
    assertEquals("world", scanner.next());

    scanner.close();
}

Обратите внимание, что метод next() возвращает здесь следующий токен String.

Также обратите внимание, как мы закрываем сканер, когда заканчиваем его использовать.

3. Преобразование InputStream в строку

Далее — давайте посмотрим, как преобразовать InputStream в строку с помощью сканера:

@Test
public void whenConvertInputStreamToString_thenConverted()
  throws IOException {
    String expectedValue = "Hello world";
    FileInputStream inputStream 
      = new FileInputStream("test.txt");
    
    Scanner scanner = new Scanner(inputStream);
    scanner.useDelimiter("A");

    String result = scanner.next();
    assertEquals(expectedValue, result);

    scanner.close();
}

Как и в предыдущем примере, мы использовали сканер для токенизации всего поток с начала к следующему регулярному выражению «A» — которое соответствует полному вводу.

4. Scanner и BufferedReader

Теперь — давайте обсудим разницу между Scanner и BufferedReader — мы обычно используем:

    BufferedReader, когда мы хотим прочитать ввод в строки Scanner для чтения ввода в строки tokens

В следующем примере мы читаем файл по строкам с помощью BufferedReader:

@Test
public void whenReadUsingBufferedReader_thenCorrect() 
  throws IOException {
    String firstLine = "Hello world";
    String secondLine = "Hi, John";
    BufferedReader reader 
      = new BufferedReader(new FileReader("test.txt"));

    String result = reader.readLine();
    assertEquals(firstLine, result);

    result = reader.readLine();
    assertEquals(secondLine, result);

    reader.close();
}

Теперь давайте воспользуемся Scanner для чтения того же файла по токенам:

@Test
public void whenReadUsingScanner_thenCorrect() 
  throws IOException {
    String firstLine = "Hello world";
    FileInputStream inputStream 
      = new FileInputStream("test.txt");
    Scanner scanner = new Scanner(inputStream);

    String result = scanner.nextLine();
    assertEquals(firstLine, result);

    scanner.useDelimiter(", ");
    assertEquals("Hi", scanner.next());
    assertEquals("John", scanner.next());

    scanner.close();
}

Обратите внимание, как мы используете Scanner nextLine() API — для чтения всей строки.

5. Сканирование входных данных из консоли с помощью нового сканера (System.in)

Далее — давайте посмотрим, как читать входные данные из консоли с помощью экземпляра сканера:

@Test
public void whenReadingInputFromConsole_thenCorrect() {
    String input = "Hello";
    InputStream stdin = System.in;
    System.setIn(new ByteArrayInputStream(input.getBytes()));

    Scanner scanner = new Scanner(System.in);

    String result = scanner.next();
    assertEquals(input, result);

    System.setIn(stdin);
    scanner.close();
}

Обратите внимание, что мы использовали System. setIn(…) для имитации некоторого ввода, поступающего из консоли.

5.1. API nextLine()

Этот метод просто возвращает строку в текущей строке:

scanner.nextLine();

Этот метод считывает содержимое текущей строки и возвращает его, за исключением любого разделителя строк в конце — в данном случае — – символ новой строки.

После прочтения содержимого Scanner устанавливает свою позицию на начало следующей строки. Важно помнить, что API nextLine() использует разделитель строк и перемещает позицию сканера на следующую строку.

Так что в следующий раз, когда мы будем читать через Scanner, мы будем читать с начала следующей строки.

5.2. API nextInt()

Этот метод сканирует следующий токен ввода как целое число:

scanner.nextInt();

API считывает целочисленный токен, доступный следующим.

В этом случае, если следующая лексема является целым числом и после целого числа есть разделитель строк, всегда помните, что nextInt() не будет использовать разделитель строк. Вместо этого положение сканера будет самим разделителем строк.

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

API nextInt() использует целое число, а API nextLine() использует разделитель строк и помещает Scanner в начало следующей строки.

6. Проверка ввода

Теперь давайте посмотрим, как проверить ввод с помощью сканера. В следующем примере мы используем метод сканера hasNextInt(), чтобы проверить, является ли ввод целым числом:

@Test
public void whenValidateInputUsingScanner_thenValidated() 
  throws IOException {
    String input = "2000";
    InputStream stdin = System.in;
    System.setIn(new ByteArrayInputStream(input.getBytes()));

    Scanner scanner = new Scanner(System.in);

    boolean isIntInput = scanner.hasNextInt();
    assertTrue(isIntInput);

    System.setIn(stdin);
    scanner.close();
}

7. Сканирование строки

Далее — давайте посмотрим, как сканировать строку. использование сканера:

@Test
public void whenScanString_thenCorrect() 
  throws IOException {
    String input = "Hello 1 F 3.5";
    Scanner scanner = new Scanner(input);

    assertEquals("Hello", scanner.next());
    assertEquals(1, scanner.nextInt());
    assertEquals(15, scanner.nextInt(16));
    assertEquals(3.5, scanner.nextDouble(), 0.00000001);

    scanner.close();
}

Примечание. Метод nextInt(16) считывает следующую лексему как шестнадцатеричное целое число.

8. Поиск шаблона

Теперь давайте посмотрим, как найти шаблон с помощью сканера.

В следующем примере мы используем findInLine() для поиска токена, соответствующего заданному шаблону, во всем вводе:

@Test
public void whenFindPatternUsingScanner_thenFound() throws IOException {
    String expectedValue = "world";
    FileInputStream inputStream = new FileInputStream("test.txt");
    Scanner scanner = new Scanner(inputStream);

    String result = scanner.findInLine("wo..d");
    assertEquals(expectedValue, result);

    scanner.close();
}

Мы также можем искать шаблон в определенном домене, используя findWithinHorizon( ) как в следующем примере:

@Test
public void whenFindPatternInHorizon_thenFound() 
  throws IOException {
    String expectedValue = "world";
    FileInputStream inputStream = new FileInputStream("test.txt");
    Scanner scanner = new Scanner(inputStream);

    String result = scanner.findWithinHorizon("wo..d", 5);
    assertNull(result);

    result = scanner.findWithinHorizon("wo..d", 100);
    assertEquals(expectedValue, result);

    scanner.close();
}

Обратите внимание, что горизонт поиска — это просто количество символов, в пределах которого выполняется поиск.

9. Пропустить шаблон

Далее — давайте посмотрим, как пропустить шаблон в сканере. Мы можем пропустить токены, соответствующие определенному шаблону, при чтении ввода с помощью Scanner.

В следующем примере мы пропускаем токен «Hello», используя метод Skip() сканера:

@Test
public void whenSkipPatternUsingScanner_thenSkipped() 
  throws IOException {
    FileInputStream inputStream = new FileInputStream("test.txt");
    Scanner scanner = new Scanner(inputStream);

    scanner.skip(".e.lo");

    assertEquals("world", scanner.next());

    scanner.close();
}

10. Изменить разделитель сканера

«Наконец, давайте посмотрим, как изменить разделитель Scanner. В следующем примере мы меняем разделитель Scanner по умолчанию на «o»:

@Test
public void whenChangeScannerDelimiter_thenChanged() 
  throws IOException {
    String expectedValue = "Hello world";
    String[] splited = expectedValue.split("o");

    FileInputStream inputStream = new FileInputStream("test.txt");
    Scanner scanner = new Scanner(inputStream);
    scanner.useDelimiter("o");

    assertEquals(splited[0], scanner.next());
    assertEquals(splited[1], scanner.next());
    assertEquals(splited[2], scanner.next());

    scanner.close();
}

Мы также можем использовать несколько разделителей. В следующем примере — мы используем обе запятые «,» и тире — в качестве разделителей для сканирования файла, содержащего «Джон, Адам-Том»:

@Test
public void whenReadWithScannerTwoDelimiters_thenCorrect() 
  throws IOException {
    Scanner scanner = new Scanner(new File("test.txt"));
    scanner.useDelimiter(",|-");

    assertEquals("John", scanner.next());
    assertEquals("Adam", scanner.next());
    assertEquals("Tom", scanner.next());

    scanner.close();
}

Примечание: Разделителем Scanner по умолчанию является пробел.

11. Заключение

В этом руководстве мы рассмотрели несколько реальных примеров использования Java Scanner.

Мы научились читать ввод из файла, консоли или строки с помощью сканера; мы также узнали, как найти и пропустить шаблон с помощью сканера, а также как изменить разделитель сканера.

Реализацию этих примеров можно найти на GitHub.