理系学生日記

おまえはいつまで学生気分なのか

split にハマる

Java で CSV ファイルをカンマで区切る処理を、RFC4180 をムシして簡単に書こうとすると*1、String#split を使うことが多いかと思います。
しかし、String#split には以下のような罠が存在します。

public class SplitTest {
	public static void main(String args[]) {
		String stripped = "a,b,c,,,";
		for ( String s : stripped.split(",") ) {
			System.out.print("[" + s + "]");
		}
		System.out.println();
                // [a][b][c]
		
		for ( String s : stripped.split(",", -1) ) {
			System.out.print("[" + s + "]");
		}
		System.out.println();
                // [a][b][c][][][]
	}
}

コメントとして出力結果を示しましたが、String#split の第二引数に負値を渡さない場合、文字列 "a,b,c,,," の末尾にあるコンマの連続は、「まるで存在しなかったかのように」処理されることになります。実際に、stripped.split(",").length は 3 になってしまいます。これを防ぐには、第二引数に負値を与えなければなりません。
恥ずかしながら、String#split のこの仕様をぼくは今日はじめて知りました。(JavaDoc には書いてあるんですけどね)


しかし、どこかでこの仕様の覚えがあるなーと思っていたら、そういえばこれ、 Perl も同じでしたね…。

use strict;
use warnings;

my $stripped = "a,b,c,,,";
foreach ( split /,/ => $stripped ) {
    print "[$_]";
}
print "\n"; # [a][b][c]

foreach ( split /,/ => $stripped, -1 ) {
    print "[$_]";
}
print "\n"; # [a][b][c][][][]

というわけなので、split には注意しましょうというお話でした。

*1:少なくとも、RFC4180 に定義された CSV を解析する処理としては正しくない