Perl tips -- リスト/抽出関係の処理

リストの操作

  まぁこんな感じです。 push,pop,shift,unsiftくらいは使えるようになった方が、 ってこれもよく書き方忘れるんだよなぁ…
#!/usr/bin/perl
@data = ("aaa","bbb","ccc","ddd");
print "#最初の状態\r\n";
&print(@data);
#
print "#一個左シフトする\r\n";
($dummy,@data) = @data;
&print(@data);
#
print "#1個右に積む\r\n";
@data = (@data,"migi-tumu");
&print(@data);
#
print "#1個左に積む\r\n";
@data = ("hidari-tumu",@data);
&print(@data);
#
print "#push 1個右に積む\r\n";
push(@data,"e");
&print(@data);
#
print "#pop 1個右から抜く\r\n";
$dummy = pop(@data);
&print(@data);
#
print "#shift 1個左から抜く\r\n";
shift(@data);
&print(@data);
#
print "#unshift 1こ左から積む\r\n";
unshift(@data,"unshift");
&print(@data);
#
#状態を表示する
sub print {
    local(@data) = @_;
    foreach (@data) {
        print " : " . $_;
    }
    print "\r\n";
}

以下は結果です。
#最初の状態
 : aaa : bbb : ccc : ddd
#一個左シフトする
 : bbb : ccc : ddd
#1個右に積む
 : bbb : ccc : ddd : migi-tumu
#1個左に積む
 : hidari-tumu : bbb : ccc : ddd : migi-tumu
#push 1個右に積む
 : hidari-tumu : bbb : ccc : ddd : migi-tumu : e
#pop 1個右から抜く
 : hidari-tumu : bbb : ccc : ddd : migi-tumu
#shift 1個左から抜く
 : bbb : ccc : ddd : migi-tumu
#unshift 1こ左から積む
 : unshift : bbb : ccc : ddd : migi-tumu

コンマで区切る(split)

  split()で区切ります。 これも正規表現が引数1個目か2個目かとか、 よく忘れているんですよねー。
#!/usr/bin/perl
$data = "abc,def,ghi";
@splitData = split(/,/,$data);
foreach(@splitData) {
    print "data: " . $_ . "\r\n";
}
#

コンマの数を数える

  ときどきやりたくなるやつです。
#!/usr/bin/perl
$data = "abc,def,ghi";
$counter = 0;
while($data =~ s/,//) {$counter++;}
print ",の数は=" . $counter;
#

csvファイルからセルを抽出する(セル内改行対策済み)

  Excelから抽出できるカンマ区切りファイル(*.csvファイル)は、 セルの中に改行があったり、セル内に「,(カンマ)」があったりすると 単純にsplit()することができません。
  対策をするには以下のようにします。
#!/usr/bin/perl

open(IN,$ARGV[0]) || die "(arg0:" . $ARGV[0] . ")$!";

@data = <IN>;
@data = commaSplit(@data);
foreach(@data) {
    @targetData = split(/,/,$_);
    $i=0;
    foreach(@targetData) {
        print $i . ":" . $_ . "\r\n";
        $i++;
    }
}

# カンマ区切り分を抽出する( ”対策)
sub commaSplit {
    local(@a) = @_;
    local(@b) = ();
    local(@targetData) = ();
    local($data,$flag);
    $data = "";
    $flag = 0;
    foreach (@a) {
        @b = split(/,/,$_);
        foreach (@b) {
            if ($flag == 0) {
                $data = $data . "," . $_;
            } else {
                $data = $data . ";" . $_; # 囲まれている
            }
            $flag = &getDouble($_,$flag);
            #print OUT $data . "\n";
        }
        if ($flag == 0) { # 囲まれなくなった
            $data =~ s/\"//g;
            $data =~ s/\'//g;
            $data =~ s/\s+//g; # 最後の改行を吹き飛ばす
            $data =~ s/^,//g; # 先頭の,はいらない
            @targetData = (@targetData,$data);
            $data = "";
        }
    }
    return(@targetData);
}

# ”の数を数える
sub getDouble {
    local($_,$flag) = @_;
    local($counter);
    $counter = 0;
    $counter++ while /\"/g;
    #print OUT "aa " . $counter . " ($_)\r\n";
    $flag = ($flag + $counter) % 2;
    return $flag;
}

#

\"の付いた"に囲まれた文章を抽出する

  "で囲まれた文章を抽出するには、 単純に/\"[\"]*\"でも良いのですが、 文章内に"があるとうまく動作しません。
  正規表現がかなりややこしいですが、 以下のような感じにすれば通ります。
#!/usr/bin/perl
#
$_ = 'print "(\")こんなのとか(\\\")こんなのが入った文章はいやだ\r\n";';
#
if (/\"((\\[rn\"]|[^\"])+)\"/) {
    print "hit : " . $1 ."\r\n";
} else {
    print "no hit :" . $_ ."\r\n";
}
#

ソートする

  ソートするにはsort()、 反転するにはreverse()を使います。
ただし、これだと単純にアスキーキャラでソートしてしまうので、 数字でソートするとかはできません。
#!/usr/bin/perl
#
@data = ("34" , "dre" , "54d" , "aee");
@data = sort @data;
@data = reverse @data;
&print(@data);
exit(0);
#
#状態を表示する
sub print {
    local(@data) = @_;
    foreach (@data) {
        print " : " . $_;
    }
    print "\r\n";
}
#
  数字のソートといったことを行うためには、 処理用の関数を作ることで対応します。
#!/usr/bin/perl
#
@data = ("34" , "23" , "1" , "115");
@data = sort number @data;
&print(@data);
exit(0);
#
#番号順に並び変える
sub number {
    if ($a < $b) {
        return -1;
    } elsif ($a == $b) {
        return 0;
    } elsif ($a > $b) {
        return 1;
    }
}
#
#状態を表示する
sub print {
    local(@data) = @_;
    foreach (@data) {
        print " : " . $_;
    }
    print "\r\n";
}
#