HHeLiBeXの日記 正道編

日々の記憶の記録とメモ‥

java.util.Scannerクラス

Java 2 SE 5.0で、java.util.Scannerクラスが追加された。


A simple text scanner which can parse primitive types and strings using regular expressions.


A Scanner breaks its input into tokens using a delimiter pattern, which by default matches whitespace. The resulting tokens may then be converted into values of different types using the various next methods.

(もともとは、java.lang.Readableインタフェースを見ていたんだけど、このインタフェースを使用するクラスがScannerクラスしかなくて、見てみたら‥という(謎))

で、見ていたら、「AWKとかと同じことができるんでは?」と思い立ち、ちょっとサンプルを書いてみた。
まず、シンプルなAWKのプログラム。

BEGIN {
    FS=",";
}
{
    printf("[%s][%s][%s]\n", $1, $2, $3);
}

これに入力として

1,1.1,1.11
2,2.2,2.22
3,3.3,3.33

のようなものを与えると、

[1][1.1][1.11]
[2][2.2][2.22]
[3][3.3][3.33]

という出力を生成する。
これと同じ処理をScannerクラスを使って書いてみる。

import java.io.StringReader;
import java.util.Scanner;
import java.util.regex.MatchResult;

public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        String data = "1,1.1,1.11\n2,2.2,2.22\n3,3.3,3.33\n";
        Scanner scanner = new Scanner(new StringReader(data));
        String pattern = "([^,\n]*),([^,\n]*),([^,\n]*)";
//        String pattern = "(\\d+),([\\d]+[.][\\d]+),([\\d]+[.][\\d]+)";
        while (scanner.findInLine(pattern) != null) {
            MatchResult match = scanner.match();
            String s1 = (match.groupCount() > 0 ? match.group(1) : null);
            String s2 = (match.groupCount() > 1 ? match.group(2) : null);
            String s3 = (match.groupCount() > 2 ? match.group(3) : null);
            System.out.printf("[%s][%s][%s]\n", s1, s2, s3);
        }
    }

}

これで、結果はAWKの場合と同じとなる。
コメントアウトしてある方のpatternを使用すると、"\\d"がdigitを表すので、1つ目が整数値、2つ目と3つ目が小数値を表す文字列として解析される。こういった正規表現を用いた解析も可能。
とりあえず、サンプルでは行あたりのトークン数は固定であると仮定しているが、match.groupCount()をちゃんと使えば行ごとにトークン数が異なっても使えるので、コマンドラインツールを作るときには役に立つかも。