【Java学習|豆知識】JavaのScannerクラスを自在に操る!useDelimiterで区切り文字をカスタマイズする方法

導入

Javaで標準入力やファイルからデータを読み込む際、デフォルトのScannerは「空白文字」を区切りとして処理します。しかし、CSVデータやログファイルなど、特定の記号で区切られたデータを取り扱う現場では、このデフォルト設定では太刀打ちできません。今回は、Scannerの区切り文字を正規表現で自由自在に変更できる、useDelimiterメソッドの活用術を解説します。これをマスターすれば、複雑なデータ形式のパーシングも非常にシンプルになります。

基礎知識

Scannerクラスは、入力ストリームをトークン(意味のある最小単位)に分割して読み込みます。デフォルトでは「空白文字(スペース、タブ、改行など)」が区切り文字として設定されています。
ここで登場するのが「正規表現(Patternクラス)」です。java.util.regexパッケージの正規表現を用いることで、「カンマやセミコロンで区切られたデータ」や「特定の文字列を境にしたデータ」を柔軟に抽出できます。特に、Named groups(名前付きグループ)を組み合わせると、読み込んだデータの意味を保持したままコードの可読性を高めることも可能です。

実装/解決策

Scannerに対してuseDelimiterメソッドを使用し、分割したいパターンを定義します。
手順は以下の通りです。
1. 分割したいルールを正規表現で定義する。
2. Pattern.compile(regex)でコンパイルする。
3. scanner.useDelimiter(pattern)を呼び出して設定を反映させる。
4. あとは通常通りnext()やnextInt()でトークンを読み込むだけです。

サンプルプログラム

以下のコードは、カンマまたはセミコロンで区切られた文字列を読み込む例です。

import java.util.Scanner;
import java.util.regex.Pattern;

public class ScannerExample {
public static void main(String[] args) {
// カンマ(,)またはセミコロン(;)を区切り文字として定義
String regex = “[,;]”;
Pattern pattern = Pattern.compile(regex);

String input = “Java,Python;C++;JavaScript;Go”;

try (Scanner scanner = new Scanner(input)) {
// 区切り文字をパターンで上書き設定
scanner.useDelimiter(pattern);

System.out.println(“読み込んだ言語リスト:”);
while (scanner.hasNext()) {
// 次のトークンを取得
String language = scanner.next();
System.out.println(“- ” + language.trim());
}
}
}
}

応用・注意点

現場で活用する際の重要な注意点がいくつかあります。

1. 正規表現の複雑化を避ける: あまりに複雑な正規表現を使用すると、処理速度が低下します。可能であれば、あらかじめPatternインスタンスを生成して使い回すようにしましょう。
2. 例外処理: Scannerは入力ソースが閉じられたり、パターンに一致しない読み込みを行おうとすると例外をスローします。try-with-resources文を必ず使用し、リソースの解放を確実に行いましょう。
3. バグの回避: useDelimiterで使用する正規表現には「空文字列」にマッチするパターンを含めないように注意してください。無限ループが発生し、アプリケーションがハングアップする原因となります。
4. Named groupsの活用: もし分割だけでなく抽出も同時に行いたい場合は、正規表現のNamed groupsを活用し、Matcherクラスを併用することで、より高度なデータ加工が可能です。

Scannerは単純なツールに見えますが、このように正規表現と組み合わせることで、簡易的なパーサーとして非常に強力な武器になります。ぜひ試してみてください。

コメント

タイトルとURLをコピーしました