1. 概要

Scanner クラスは、正規表現を使用してプリミティブ型と文字列を解析できる便利なツールであり、Java5のjava.utilパッケージに導入されました。

この短いチュートリアルでは、その hasNext()および hasNextLine()メソッドについて説明します。 これらの2つの方法は、最初はかなり似ているように見えますが、実際にはまったく異なるチェックを行っています。

汎用性の高いスキャナークラスの詳細については、こちらのクイックガイドをご覧ください。

2. hasNext()

2.1. 基本的な使用法

hasNext()メソッドは、Scannerの入力に別のトークンがあるかどうかを確認します。 スキャナーは、デフォルトで空白に一致する区切り文字パターンを使用して入力をトークンに分割します。つまり、 hasNext()は入力をチェックし、trueを返します。別の非空白文字があります。

デフォルトの区切り文字に関するいくつかの詳細にも注意する必要があります。

  • ホワイトスペースには、スペース文字だけでなく、タブスペース( \ t )、改行( \ n )、およびさらに多くの文字も含まれます。
  • 連続した空白文字は単一の区切り文字として扱われます
  • 入力の最後の空白行は印刷されません。つまり、 hasNext()は、空白行に対してfalseを返します。

hasNext()がデフォルトの区切り文字でどのように機能するかの例を見てみましょう。 まず、S cannerの解析結果を調べるのに役立つ入力文字列を準備します。

String INPUT = new StringBuilder()
    .append("magic\tproject\n")
    .append("     database: oracle\n")
    .append("dependencies:\n")
    .append("spring:foo:bar\n")
    .append("\n")  // Note that the input ends with a blank line
    .toString();

次に、入力を解析して結果を出力しましょう。

Scanner scanner = new Scanner(INPUT);
while (scanner.hasNext()) {
    log.info(scanner.next());
}
log.info("--------OUTPUT--END---------")

上記のコードを実行すると、コンソール出力が表示されます。

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring:foo:bar
[DEMO]--------OUTPUT--END---------

2.2. カスタム区切り文字付き

これまで、デフォルトの区切り文字を使用した hasNext()について見てきました。 Scanner クラスは、区切り文字を変更できるuseDelimiter(String pattern)メソッドを提供します。 区切り文字が変更されると、 hasNext()メソッドは、デフォルトの区切り記号ではなく、新しい区切り記号を使用してチェックを実行します。

hasNext()および next()がカスタム区切り文字とどのように連携するかについての別の例を見てみましょう。 最後の例の入力を再利用します。

スキャナーが文字列「dependencies:」に一致するトークンを解析した後、区切り文字をコロン( 🙂 に変更して、依存関係の各値を解析および抽出できるようにします。 :

while (scanner.hasNext()) {
    String token = scanner.next();
    if ("dependencies:".equals(token)) {
        scanner.useDelimiter(":");
    }
    log.info(token);
}
log.info("--------OUTPUT--END---------");

結果の出力を見てみましょう:

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]
spring
[DEMO]foo
[DEMO]bar


[DEMO]--------OUTPUT--END---------

すごい! 「dependencies」の値は正常に抽出されましたが、予期しない改行の問題がいくつかあります。 これらを回避する方法については、次のセクションで説明します。

2.3. 区切り文字として正規表現を使用

前のセクションの出力を確認してみましょう。 まず、「 spring 」の前に改行( \ n )があることに気づきました。 「依存関係:」トークンがフェッチされた後、区切り文字を「」に変更しました。 「dependencies:」の後の改行は、次のトークンの一部になります。 したがって、 hasNext() true を返し、改行が出力されました。

同じ理由で、「 hibernate 」の後の改行と最後の空白行が最後のトークンの一部になるため、2つの空白行が「hibernate」と一緒に印刷されます。

コロンと空白の両方を区切り文字として作成できれば、「依存関係」の値が正しく解析され、問題が解決されます。 これを実現するために、 useDelimiter(“:”)呼び出しを変更してみましょう。

scanner.useDelimiter(":|\\s+");

ここでの「:| \\ s + 」は、単一の「:」または1つ以上の空白文字に一致する正規表現です。 この修正により、出力は次のようになります。

[DEMO]magic
[DEMO]project
[DEMO]database:
[DEMO]oracle
[DEMO]dependencies:
[DEMO]spring
[DEMO]foo
[DEMO]bar
[DEMO]--------OUTPUT--END---------

3. hasNextLine()

hasNextLine()メソッドは、行が空白であるかどうかに関係なく、Scannerオブジェクトの入力に別の行があるかどうかを確認します。

同じ入力をもう一度取りましょう。 今回は、 hasNextLine()および nextLine()メソッドを使用して、入力の各行の前に行番号を追加します。

int i = 0;
while (scanner.hasNextLine()) {
    log.info(String.format("%d|%s", ++i, scanner.nextLine()));
}
log.info("--------OUTPUT--END---------");

それでは、出力を見てみましょう。

[DEMO]1|magic	project
[DEMO]2|     database: oracle
[DEMO]3|dependencies:
[DEMO]4|spring:foo:bar
[DEMO]5|
[DEMO]--------OUTPUT--END---------

予想通り、行番号が印刷され、最後の空白行もそこにあります。

4. 結論

この記事では、 Scanner hasNextLine()メソッドが、行が空白であるかどうかに関係なく、入力に別の行があるかどうかをチェックすることを学びました。 X176X] hasNext()は、区切り文字を使用して別のトークンをチェックします。

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