小池啓仁 ヒロヒト応援ブログ By はてな

小池啓仁(コイケヒロヒト)の動画など。

小池啓仁 ヒロヒト応援ブログ By はてな

動的に配列のハッシュを作る

たとえば、'aaa=111&bbb=222&bbb=333&bbb=444&ccc=555&ddd=666&ddd=777'という文字列があったとします。
これを入力データとして、以下のような普通のハッシュと配列のハッシュが混在したハッシュ(%FORM)を作ってみます。

$FORM{aaa}=111
$FORM{bbb}[0]=222     $FORM{bbb}[1]=333     $FORM{bbb}[2]=444
$FORM{ccc}=555
$FORM{ddd}[0]=666     $FORM{ddd}[1]=777

ソース(hh.pl)

use strict;
# 入力データ
my $buffer = 'aaa=111&bbb=222&bbb=333&bbb=444&ccc=555&ddd=666&ddd=777';

# ハッシュと配列のハッシュの混合ハッシュを作成する。
my %FORM = &hash_hairetu($buffer);

# 以下は上記のデータをプリントする。
foreach my $i (sort keys %FORM) {
    if (ref($FORM{$i}) eq "ARRAY") {
        for (my $j = 0; $j <= $#{$FORM{$i}}; $j++) {
            print '$FORM{' . $i . '}[' . $j . ']=' . $FORM{$i}[$j] . '     ';
        }
        print "\n";
    }
    else {
        print '$FORM{' . $i . '}=' . $FORM{$i} , "\n"
    }
};

#ハッシュの中が配列リファレンスだったらその配列データを返す。
my @data = hairetu_filter($FORM{bbb});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

#ハッシュの中がデータだったらそのデータを返す。
@data = hairetu_filter($FORM{aaa});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

# ハッシュの中が空だったら空を返す。
@data = hairetu_filter($FORM{xxx});
print '$#data=' . $#data . "\n";
for (my $i = 0; $i <= $#data; $i++) {
    print 'data[' . $i . ']=' . $data[$i], "\n";
}

# ハッシュと配列のハッシュを返すサブルーチン
sub hash_hairetu {
    my ($buffer) = @_;
    my ($name, $value);
    my %FORM = ();
    my @wk = ();
    my $i = 0;
    my @pairs = split(/&/, $buffer);
    foreach my $pair (@pairs) {
        ($name, $value) = split(/=/, $pair);
        if (exists $FORM{$name}) {
            if ($i == 0) {
                $wk[$i++] = $FORM{$name};
            }
            $wk[$i++] = $value;
            $FORM{$name} = [ @wk ];
        }
        else {
            $i = 0;
            @wk = ();
            $FORM{$name} = $value;
        }
    }
    return %FORM;
}

# ハッシュの中が配列リファレンスだったらその配列データを返すサブルーチン
sub hairetu_filter {
    my ($para) = @_;
    my @wk = ();
    if (ref($para) eq "ARRAY") {
        @wk = @$para;
    }
    elsif (defined($para)) {
        $wk[0] = $para;
    }
    return @wk; 
}

出力プリント

C:\test>perl hh.pl
$FORM{aaa}=111
$FORM{bbb}[0]=222     $FORM{bbb}[1]=333     $FORM{bbb}[2]=444
$FORM{ccc}=555
$FORM{ddd}[0]=666     $FORM{ddd}[1]=777
$#data=2
data[0]=222
data[1]=333
data[2]=444
$#data=0
data[0]=111
$#data=-1

ポイント解説

$FORM{$name} = [ @wk ];は、ハッシュに配列(@wk)のデータを無名配列コンストラクタを使用してそのリファレンスを格納する。
if (exists $FORM{$name}) { は、ハッシュキーが存在するかを判定する。
if (ref($para) eq "ARRAY") { は、ハッシュの要素が配列リファレンスかを判定する。