splitのクセ・落とし穴(split)


splitのクセ・落とし穴(split)


CSVのような分割を想定した文字列の場合、カンマなどの分割文字が決まっているので、その文字をあてれば分割することができるが、分割文字列はケースによって変わることついて考えてみる。

ケース1

Perlのsplitは分割文字を文字列の文字として評価していないため実行すると分割文字は削除される。

$a = "0123456789";
@ary = split('5', $a);
print "ary[0]=\"".$ary[0]."\"\n";
print "ary[1]=\"".$ary[1]."\"\n";
printf "ary[0].length=%d\n", length($ary[0]);	# 0番目文字長
printf "ary[1].length=%d\n", length($ary[1]);	# 1番目文字長

結果

ary[0]="01234"
ary[1]="6789"
ary[0].length=5		# ary[0]の文字長は5文字
ary[1].length=4		# ary[1]の文字長は4文字


もしこのような場合、分割文字に何らかの代替文字(例えばタブ文字とか)に予め置換してからsplitを実行する。

$a = "0123456789";
$a =~ s/5/\t5/g;		# 分割文字を5からタブに変更する
my @ary = split("\t", $a);	# タブでsplitする
print "ary[0]=\"".$ary[0]."\"\n";
print "ary[1]=\"".$ary[1]."\"\n";
printf "ary[0].length=%d\n", length($ary[0]);	# 0番目文字長
printf "ary[1].length=%d\n", length($ary[1]);	# 1番目文字長

結果

ary[0]="01234"
ary[1]="56789"
ary[0].length=5
ary[1].length=5

ケース2

分割文字が対象文字列の先頭に含まれていた場合は次のようになる。

my $a = "0123456789";
my @ary = split("0", $a);
print "ary[0]=".$ary[0]."\n";
print "ary[1]=".$ary[1]."\n";
printf "ary[0].defined=%d\n", defined($ary[0]);	# 0番目は定義済み
printf "ary[1].defined=%d\n", defined($ary[1]);	# 1番目は定義済み
printf "ary[0].length=%d\n", length($ary[0]);	# 0番目文字長
printf "ary[1].length=%d\n", length($ary[1]);	# 1番目文字長

結果

ary[0]=""
ary[1]="123456789"
ary[0].defined=1
ary[1].defined=1
ary[0].length=0
ary[1].length=9

ケース3

分割文字が対象文字列の最後に含まれていた場合は次のようになる。

my $a = "0123456789";
my @ary = split("9", $a);
print "ary[0]=".$ary[0]."\n";
print "ary[1]=".$ary[1]."\n";
printf "ary[0].defined=%d\n", defined($ary[0]);	#
printf "ary[1].defined=%d\n", defined($ary[1]);	# 1番目は未定義
printf "ary[0].length=%d\n", length($ary[0]);	# 0番目文字長
printf "ary[1].length=%d\n", length($ary[1]);

結果

ary[0]="012345678"
ary[1]=""
ary[0].defined=1
ary[1].defined=0
ary[0].length=9
ary[1].length=0

ケース4

分割文字が対象文字列に含まれなかった場合、ケース3に似た結果になる。

my $a = "0123456789";
my @ary = split("A", $a);			# splitに失敗しているので $ary[0] = $a となる
print "ary[0]=".$ary[0]."\n";
print "ary[1]=".$ary[1]."\n";
printf "ary[0].defined=%d\n", defined($ary[0]);	# 0番目に$aがそのまま代入される
printf "ary[1].defined=%d\n", defined($ary[1]);	# 1番目は未定義

結果

ary[0]="0123456789"
ary[1]=""
ary[0].defined=1
ary[1].defined=0
ary[0].length=10
ary[1].length=0

ケース3とケース4の明らかな違いは結果の文字数で、ケース3では分割文字を削除して結果を出力するのに対し、ケース4では分割文字が対象文字列に含まれなかったので、対象文字列はary[0]にそのままコピーされた形になる。

結果を注意深く見ていないと、splitが成功していたのか失敗していたのか判別しにくく、defindの結果や1番目の要素の文字列がヌルか否かを分岐条件にすると、潜在的なエラーを生じることになる。

Task Runner