1. 概要

このチュートリアルでは、ScannerクラスのuseDelimiterメソッドの使用方法を説明します。

2. java.util.Scannerの概要

Scanner APIは、シンプルなテキストスキャナーを提供します。

デフォルトでは、スキャナーは入力を区切り文字として空白を使用してトークンに分割します。次のような関数を記述してみましょう。

  • 入力をスキャナーに渡します
  • スキャナーを繰り返し処理して、リスト内のトークンを収集します

基本的な実装を見てみましょう。

public static List<String> baseScanner(String input) {
    try (Scanner scan = new Scanner(input)) {
        List<String> result = new ArrayList<String>();
        scan.forEachRemaining(result::add);
        return result;
    }
}

このコードでは、try-with-resourcesを使用してScannerを作成したことに注意してください。 これが可能なのは、ScannerクラスがAutoCloseableインターフェースを実装しているためです。 このブロックは、スキャナーリソースを自動的に閉じる役割を果たします。 Java 7より前は、 try-with-resources を使用できなかったため、手動で処理する必要がありました。

また、 Scanner 要素を反復処理するために、forEachRemainingメソッドを使用したことにも気付くでしょう。 この方法はJava8で導入されました。 ScannerはIteratorを実装しており、古いJavaバージョンを使用した場合は、それを利用して要素を反復処理する必要があります。

前述したように、 Scanner は、入力を解析するためにデフォルトで空白を使用します。 たとえば、 baseScannerメソッドを「WelcometoBaeldung」と入力して呼び出すと、「Welcome」、「to」、「Baeldung」の順序付けられた要素を含むリストが返されます。

メソッドが期待どおりに動作することを確認するためのテストを作成しましょう。

@Test
void whenBaseScanner_ThenWhitespacesAreUsedAsDelimiters() {
    assertEquals(List.of("Welcome", "to", "Baeldung"), baseScanner("Welcome to Baeldung"));
}

3. カスタム区切り文字を使用する

次に、カスタム区切り文字を使用するようにスキャナーを設定しましょう。 スキャナーが入力を中断するために使用する文字列を渡します。

それをどのように行うことができるか見てみましょう:

public static List<String> scannerWithDelimiter(String input, String delimiter) {
    try (Scanner scan = new Scanner(input)) {
        scan.useDelimiter(delimiter); 
        List<String> result = new ArrayList<String>();
        scan.forEachRemaining(result::add);
        return result;
    }
}

いくつかの例についてコメントしましょう。

  • 区切り文字として単一の文字を使用できます。必要に応じて、文字をエスケープする必要があります。 たとえば、基本的な動作を模倣し、区切り文字として空白を使用する場合は、「\\s」を使用します。
  • 任意の単語/フレーズを区切り文字として使用できます
  • 区切り文字として複数の可能な文字を使用できます。このためには、|で区切る必要があります。 たとえば、すべての空白とすべての改行の間で入力を分割する場合は、次の区切り文字を使用します:“ \ n | \\ s”
  • 一言で言えば、区切り文字として任意の種類の正規表現を使用できます。たとえば、「a+」は有効な区切り文字です。

最初のケースをテストする方法を見てみましょう。

@Test
void givenSimpleCharacterDelimiter_whenScannerWithDelimiter_ThenInputIsCorrectlyParsed() {
    assertEquals(List.of("Welcome", "to", "Baeldung"), scannerWithDelimiter("Welcome to Baeldung", "\\s"));
}

実際には、シーンの下で、useDelimiterメソッドはその入力をPatternオブジェクトにカプセル化された正規表現に変換します。または、Patternのインスタンス化を自分で処理することもできます。 このためには、次に示すように、オーバーライドする useDelimiter(パターンパターン)を使用する必要があります。

public static List<String> scannerWithDelimiterUsingPattern(String input, Pattern delimiter) {
    try (Scanner scan = new Scanner(input)) {
        scan.useDelimiter(delimiter); 
        List<String> result = new ArrayList<String>();
        scan.forEachRemaining(result::add);
        return result;
    }
}

Pattern をインスタンス化するには、次のテストのようにcompileメソッドを使用できます。

@Test
void givenStringDelimiter_whenScannerWithDelimiterUsingPattern_ThenInputIsCorrectlyParsed() {
    assertEquals(List.of("Welcome", "to", "Baeldung"), DelimiterDemo.scannerWithDelimiterUsingPattern("Welcome to Baeldung", Pattern.compile("\\s")));
}

4. 結論

この記事では、useDelimiter関数を呼び出すために使用できるパターンの例をいくつか紹介しました。 デフォルトでは、 Scanner は空白の区切り文字を使用していることに気付き、そこではあらゆる種類の正規表現を使用できることを指摘しました。

いつものように、完全なコードはGitHubから入手できます。