JavaにおけるScannerクラス
Java Scannerクラスは、java.utilパッケージの一部です。これはJava 1.5リリースで導入されました。Scannerは、主にユーザーの入力を受け取り、int、double、またはデフォルトのStringなどのプリミティブデータ型にパースするために使用されます。これは、トークンを生成することで正規表現を使用してデータを解析するためのユーティリティクラスです。
JavaのScannerクラスのコンストラクター
Scannerクラスを見ると、たくさんのコンストラクタがあります。
多くの建設業者は、3つのオブジェクトのうちの1つを使用しています。
-
- ストリーム – ユーザー入力を受け取るために System.in を渡す一般的な方法です。
-
- ファイルまたはパス – ファイルデータをスキャンし、ファイルからの値を処理することもできます。
- 文字列 – 文字列ソースに対してスキャナーを作成し、そこから値を解析することもできます。
もし第二引数を見ると、パースする際にデフォルトの文字セットを使用したくない場合に、文字セットを指定するためです。
Scannerクラスの重要なメソッド
よく利用されるScannerクラスのメソッドを見てみましょう。
- useDelimiter(String pattern) – the delimiter to be used for the scanner. The default delimiter is whitespace.
- hasNext() – returns true if there is another token in the input. It’s a blocking method and it will keep waiting for user input.
- next() – returns the next token from the scanner. It’s used in conjunction with the hasNext() method.
- close() – scanner is resource heavy, so once you are done with it, use this method to close it and release system resources.
入力トークンをint、short、long、byte、BigDecimalなどに直接解析し、チェックするための便利なメソッドが多数あります。
スキャナを初期化して使用するための手順
-
- 最初のステップは、InputStream、File、またはStringなどの入力タイプに基づいた適切なコンストラクタを使用して、スキャナークラスを初期化することです。必要に応じて、デリミタや文字セットを設定します。
-
- 2番目のステップは、hasNext()メソッドを使って入力トークンを待つことです。
- 次に、next()メソッドを使用してトークンを読み込み、1つずつ処理します。
スキャナーはどのように動作するのですか?(Sukyanā wa dono yō ni dōsa suru nodesu ka?)
- The Scanner class breaks its input into tokens using the specified delimiter pattern.
- The next() methods is used to read the tokens one by one and process them.
- Finally, close the Scanner instance to release the system resources.
スキャナーの例
– スキャナーの使用例
私たちは、いくつかの共通のScannerクラスの使用法を、サンプルコードのスニペットと共に見てみましょう。
ユーザーの入力を読み取る。
これはScannerクラスの最も一般的な使い方です。入力元としてSystem.inを使用してインスタンスを生成し、ユーザーの入力を読み取ることができます。
// read user input
Scanner sc = new Scanner(System.in);
System.out.println("Please enter your name");
String name = sc.next();
System.out.println("Hello " + name);
sc.close();
出力:
Please enter your name
Pankaj
Hello Pankaj
うーん、簡単そうで、うまく機能しているように見えますね。しかし、上記のコードには問題があります。次のセクションを読まずに、コードを確認して問題点を見つけていただけますか?
入力欄に自分のフルネームを書いてみて、何が起こるか見てみましょう。
Please enter your name
Pankaj Kumar
Hello Pankaj
今、理解しているはずですが、それは空白が区切り文字だから起こっています。スキャナーは入力を2つのトークン、つまり”Pankaj”と”Kumar”に分割しています。しかし、私たちはnext()メソッドを一度しか呼び出していないので、”Hello Pankaj”のみが出力されます。
これをどう直せばいいですか? (Kore o dou naoseba ii desu ka?)
簡単です。useDelimiter() メソッドを使用して改行文字に区切り記号を変更することができます。
Scanner sc = new Scanner(System.in);
sc.useDelimiter(System.getProperty("line.separator"));
System.out.println("Please enter your name");
String name = sc.next();
System.out.println("Hello " + name);
sc.close();
2. Scannerを使用してファイルデータを解析する。
シンプルな例を見て、スキャナクラスを使用してCSVファイルを読み込み、パースする方法を見てみましょう。以下の内容を持つemployees.csvファイルがあるとしましょう。
1,Jane Doe,CEO
2,Mary Ann,CTO
3,John Lee,CFO
Javaプログラムでファイルを読み込んで従業員のリストを取得しましょう。
package com.scdev.java;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class ScannerExamples {
public static void main(String[] args) throws IOException {
// create scanner for the CSV file
Scanner sc = new Scanner(new File("employees.csv"));
// set delimiter as new line to read one line as a single token
sc.useDelimiter(System.getProperty("line.separator"));
// create the List of Employees
List<Employee> emps = new ArrayList<>();
while (sc.hasNext()) {
Employee emp = parseEmployeeData(sc.next());
emps.add(emp);
}
// close the scanner
sc.close();
// print employee records
System.out.println(emps);
}
private static Employee parseEmployeeData(String record) {
// create scanner for the String record
Scanner sc = new Scanner(record);
// set delimiter as comma
sc.useDelimiter(",");
Employee emp = new Employee();
emp.setId(sc.nextInt());
emp.setName(sc.next());
emp.setRole(sc.next());
// close the scanner
sc.close();
return emp;
}
}
class Employee {
private int id;
private String name;
private String role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public String toString() {
return "Emp[" + id + "," + name + "," + role + "]";
}
}
- The first step is to create the scanner for the CSV file and set newline as delimiter.
- Then for each line that contains employee record in CSV format, parse it using another scanner and comma as delimiter. The parseEmployeeData() is parsing each line and creating Employee object.
- Finally, we are adding the employee object to the list and printing it.
出力:[Emp[1,ジェーン・ドウ,CEO]、Emp[2,メアリー・アン,CTO]、Emp[3,ジョン・リー,CFO]]
3. JavaのScanner正規表現の例
「仮に、私たちには文字列のソースがあり、それに含まれる整数のみを処理したいとします。非数字の正規表現を使用して、整数のみをトークンとして取得し、それらを処理するためにスキャナーを使用できます。」
//using regex to read only integers from a string source
String data = "1a2b345c67d8,9#10";
Scanner sc1 = new Scanner(data);
// setting non-digit regex as delimiter
sc1.useDelimiter("\\D");
while(sc1.hasNext()) {
System.out.println(sc1.next());
}
// don't forget to close the scanner
sc1.close();
出力:
1
2
345
67
8
9
10
結論
JavaのScannerは、ユーザーの入力を読み取ったり、単純な正規表現ベースのファイルや文字列ソースのパースを行うためのユーティリティクラスです。しかし、実際のアプリケーションでは、ScannerクラスではなくCSVパーサーを使用することで、CSVデータのパースをより高速に行うことができます。
参考:APIドキュメント、Javaでの正規表現