Javaスキャナー

1概要

このチュートリアルでは、 Java Scanner を使用して入力を読み取り、さまざまな区切り文字を持つパターンを見つけてスキップする方法を説明します。

2ファイルをスキャンする

まず、 Scanner を使用してファイルを読み取る方法を見てみましょう。次の例では、 Scanner を使用して「 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();
}

注: Scanner メソッド next() は、次の String トークンを返します。

3 InputStream String に変換

次に、 Scanner を使用して InputStream String に変換する方法を見てみましょう。

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

注:前の例では、 Scanner をトリックして、ストリーム全体を先頭から次の正規表現「A」(入力の先頭に一致)までトークン化しました。

4 Scanner BufferedReader

それでは、 Scanner BufferedReader の違いについて説明しましょう。

  • BufferedReader 入力を行に読みたいとき**

入力を トークンに読み込む Scanner

次の例では、 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 new Scanner(System.in)を使用したコンソールからのスキャン入力

次に、 Scanner を使用してコンソールから入力を読み取る方法を見てみましょう。

@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. nextLine() API

このメソッドは単に現在行の文字列を返します。

scanner.nextLine();

これは現在の行の内容を読み取り、最後の行区切り文字(この場合は改行文字)を除いてそれを返します。

内容を読んだ後、 Scanner はその位置を次の行の先頭に設定します。覚えておくべき重要な点は、** __ nextLine() APIが行区切り文字を消費し、 Scanner__の位置を次の行に移動することです。

そのため、次回は__Scannerを介して読む場合は、次の行の先頭から読みます。

5.2. nextInt() API

このメソッドは、入力の次のトークンを int: としてスキャンします。

scanner.nextInt();

APIは次に利用可能な整数トークンを読み取ります。この場合、次のトークンが整数でその整数の後に行区切り記号がある場合は、必ず __ nextInt() __が行区切り記号を消費しないことを忘れないでください。代わりに、スキャナの位置は行区切り文字そのものになります

そのため、最初の操作が scanner.nextInt() 、次に scanner.nextLine() で、一連の操作がある場合は、整数を指定して改行を押すと入力として、両方の操作が実行されます。

nextInt() APIは整数を消費し、 nextLine() APIは行区切り文字を消費し、 Scanner を次の行の先頭に配置します。

6. 入力を検証

それでは、 Scanner を使用して入力を検証する方法を見てみましょう。次の例では、 Scanner メソッド 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. String をスキャン

次に、 Scanner を使用して String をスキャンする方法を見てみましょう。

@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) は、次のトークンを16進整数値として読み取ります。

8 Pattern を探す

それでは、 Scanner を使用して Pattern を見つける方法を見てみましょう。

次の例では、 findInLine() を使用して、入力全体で指定された Pattern に一致するトークンを 検索します。

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

次の例のように、 findWithinHorizo​​n() を使用して特定のドメイン内の Pattern を検索することもできます。

@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 Pattern をスキップする方法を見てみましょう。 Scanner を使用して入力を読み取るときに、特定のパターンに一致するトークンをスキップできます。

次の例では、 Scanner メソッド skip() を使用して「 Hello 」トークンをスキップします。

@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 区切り文字を変更する方法を見てみましょう。次の例では、デフォルトの 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();
}

複数の区切り文字を使用することもできます。次の例では、ファイルをスキャンするための区切り文字として、カンマ“ ”とダッシュ“ ”の両方を使用しています。“ John、Adam-Tom

@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 を使った実際の例をいくつか調べました。

Scanner を使用して、ファイル、コンソール、または String から入力を読み取る方法を学びました。 Scanner を使用してパターンを見つけてスキップする方法、および Scanner 区切り文字を変更する方法も学習しました。

これらの例の実装はhttps://github.com/eugenp/tutorials/tree/master/core-java-io[GitHubで公開]にあります - これはMavenベースのプロジェクトなので、インポートは簡単ですそのまま実行します。