テキスト処理
BufferedReader, PrintWriter
Text File の I/O 事例をいくつか紹介します。 で、ここで扱うのは、一行単位で読み込むプログラムの例です(UseBufferedIO)。
今度は、標準出力に結果を表示しながら、sample2.out
というファイルも生成します。
出力はこんな感じ(入力ファイルを準備したのは、両大学の統合以前なのでご了承を)。
0 http://en.wikipedia.org/wiki/Osaka_Prefecture_University 大阪府立大学 34.54777908325195 135.5075073242188
1 http://en.wikipedia.org/wiki/Osaka_City_University 大阪市立大学 34.59055709838867 135.5050048828125
こちらはプログラム:
private static void copyfile(String from, String to)
throws IOException {
/* File読み込み用Reader */
BufferedReader in = new BufferedReader(new FileReader(from));
/* File出力用PrintWriter */
PrintWriter out = new PrintWriter(to);
try {
String line;
int i = 0;
while ((line = in.readLine()) != null) { /* 一行read */
String outline = i + ":" + line; /* 行番号つけて */
System.out.println(outline); /* 標準出力にprint */
out.println(outline); /* ファイルにもprint */
i++;
}
} finally {
in.close();
out.close(); /* PrintWriter の close()処理 */
}
}
まず、このプログラムを簡単に解説しておくと、主な登場人物は、以下のふたつ。
- java.io.BufferedReader
- java.io.FileReader 経由で作成
readLine()
: 一行単位でデータを読み込む機能を提供
- java.io.PrintWriter
- ファイル名指定して作成
- 各種 print(), println() メソッドを提供。
- System.out や System.err と同じように使える。
入力用 BufferedReader
の生成:
- ファイルを読む場合は、前述どおりファイル名を指定してjava.io.FileReader経由で作成する。
BufferedReader in = new BufferedReader(new FileReader(filename));
- 標準入力から読む場合は、InputStream→Reader変換をしてあげましょう。
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
出力用 PrintWriter
の生成
- ファイルを出力する場合は、前述の様にファイル名を指定して作成するだけ。
- 標準出力に出力する場合は、System.out に対し println(), print() などを呼べばいいでしょう。
- あるいは、OutputStreamWriter経由で使うこともできます。
new PrintWriter(new OutputStreamWriter(System.out))
で変換できます。 - ファイル入出力と標準入出力を切り替えたければ、java.lang.System クラスの
setIn/Out/Err
メソッドを使って、標準入出力自身を切り替えるという手もあります。
- あるいは、OutputStreamWriter経由で使うこともできます。
おまけ情報
: java.nio.file.Files は、各種 I/O 用途の static method が備わった便利なクラスです。
newBufferedReader(Path)
などのメソッドも提供されているので、こちらを使うのでも構いません。
文字コード
テキスト処理を行う上で、面倒な話を少し。日本語を処理していると文字コードがいろいろあります。
- UTF8 (演習室で標準設定)
- EUC-JP
- ISO-2022-JP, jis
- MS932 (いわゆる shift JIS。Windows 系で標準的扱い)
FileReader
や PrintWriter
は、文字コードを意識した処理が可能で、入力ファイルの文字セットを指定出来るようになっています。
指定されていない場合は、システム標準の文字セットで処理を行います。指定する際は、例えば以下のようにすればOKです。
BufferedReader in = new BufferedReader(new InputStreamReader(new FileInputStream(filename), "UTF8"));
後述する java.util.Scanner の場合は、こんな感じ。
Scanner sc = new Scanner(new File(filename), "UTF8");
String line = sc.nextLine();
などとすると良いでしょう。
便利な文字セット指定にJISAutoDetect
というのもあります。ISO2022, EUC, Shift JIS などを自動判定します。
語句単位のテキスト処理
次は、java.util.Scanner を使って、語句単位の処理をしてみましょう(UseScanner)。
で、プログラムのコア部分がこちら。
while (in.hasNext()) {
String url = in.next();
String name = in.next();
double lat = in.nextDouble();
double lon = in.nextDouble();
System.out.println("名前:" + name + ", 緯度:" + lat +
", 経度" + lon + ", Wikipedia URL: " + url);
}
主な利用クラス
- java.util.Scanner
- コンストラクタには、file名 や Input Stream を引数として与える。文字セットも指定可能。
delimiter(区切り文字)指定
:useDelimiter(java.util.regex.Pattern)
しない限り、空白相当を切れ目に word に切り分けてくれるnext()
: 次の word を取得nextInt()
: 次の word を int に変換して取得。その他基本データ型用メソッドもありhasNext()
: 次の word の有無を返す。基本データ型版も存在。
ということで、このプログラムの場合、冒頭の url と 大学名を String として取り出し、緯度経度を double で取得しています。 結構便利です。
-
Scanner は、String に対しても利用可能なので、文字列をバラしたいときにもどうぞ。他にも、対象が String であれば、String クラスの
split()
メソッドや、java.util.StringTokenizer`クラスもあります。 -
これらのクラスは、delimiter の指定に正規表現を用いることもできます。正規表現というのは、文字列の連結, 選択(|),繰り返し(*,+)などを使って、文字列群を表現する方法です。
例:- “,”: “,” (1文字)を区切り文字とする
- “, “: “, " (2文字の連なり)を区切り文字とする
- “,| “: “,” もしくは " " を区切り文字とする
- “,+”: “,” の1文字以上の繰り返し(+) を区切り文字とする
- “(,| )+”: 「”,” もしくは " “」の1回以上の繰り返し(+) を区切り文字とする
- “(, )+”: “, " (2文字)の1回以上の繰り返し(+) を区切り文字とする
- 各種文字クラスの表現は、java.util.regex.Patternの説明を読んでください。空白、アルファベット、数字などをまとめて表現する方法も載っています。
-
正規表現は、文字列マッチや置換処理にも使えます。
String#matches(regex)
: String が正規表現にマッチするかString#replaceAll(regex, replace)
: 置換