StringTokenizerでCSVを処理するときの注意点

Posted by mkamo on 2008年7月4日

StringTokenizerでCSVを処理するときの注意点のメモ.

Googleで「csv java」で検索するとStringTokenizerを使ってCSV形式の文字列を処理するいくつかの例が見つかるが,これらの例には注意しないといけない点がある.具体的には,"foo,,baz"といった,一部の列に値が存在しないために「,」が続くような文字列が入力された場合,"foo"と"baz"だけが処理対象となってしまう.一般的に期待するのは"foo"と""(空文字)と"bar"が処理対象となることだろう.

Googleで見つかるStringTokenizerを使ったCSV処理の例から,列の分割処理だけを切り出して整えるとだいたい以下のようなコードになる.

private static String[] splitLineWithComma(String line) {
    if (line == null) {
        return new String[0];
    }

    List<String> ret = new ArrayList<String>();

    StringTokenizer tokenizer = new StringTokenizer(line, ",");
    while (tokenizer.hasMoreTokens()) {
        ret.add(tokenizer.nextToken());
    }

    return (String[]) ret.toArray(new String[ret.size()]);
}

このコードは"foo,bar,baz"といったすべての列に値が入っている文字列に対しては期待通りに"foo"と"bar"と"baz"が入った配列を返す.しかし,"foo,,baz"といった,一部の列に値が存在しないために「,」が続くような文字列に対しては期待通りの結果を返さない.StringTokenizerが「,」と「,」の間の""をトークンとはみなせないために,"foo"と"bar"だけが入った配列を返してしまう.

単純にカンマで区切るだけでよいのならJDK 1.4以上であれば line.split(",", -1)とすればよいし,それ以前のバージョンのJDKであれば以下のようなコードでよい.

private static String[] splitLineWithComma(String line) {
    if (line == null) {
        return new String[0];
    }

    List ret = new ArrayList();

    int colStart = 0;
    int colEnd = 0;
    while ((colEnd = line.indexOf(',', colStart)) != -1) {
        ret.add(line.substring(colStart, colEnd));
        colStart = colEnd + 1;
    }

    ret.add(line.substring(colStart));

    return (String[]) ret.toArray(new String[ret.size()]);
}


コメントを書く




XHTML: 次のタグが使用できます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Please note: 投稿されたコメントが表示されるにはいくらかの時間がかかります.投稿後直ちに表示されませんが投稿ボタンを何度も押さないようお願いします.