Subscribed unsubscribe Subscribe Subscribe

SE Can't Code

A Tokyo based Software Engineer. Not System Engineer :(

Perlで簡単なツールを作った時のTips

しょぼいけれど最近作ったツールを元に学んだことを、ツールの一部とともにあげておく。 よく会社でツールを作るのだけれど、最初に作ったツールPerlだったのでそれ以降すべてPerlで書いている。SIerなので文字列操作が多く、正規表現の強いPerlを使うかぁというのが背景。しかし自分以外Perlかじっている人間がいないのもある上、Perlって可読性がイマイチなので今後のことを考えるときっとよろしくないのだろうな、と思いつつPerlで書いてる。

以下が最近暇を見つけて書いたコード。意図する二つのcsvファイルを開いてその二つの内容が一致しているよね?ということを確認するためだけのツールで、しょぼすぎてくらくらするけれど、一応突合時に一回一回ファイルオープンしないよう事前に多次元配列にぶち込んだりということは考えてやってたりする。(それもそれでしょぼいけど) 言い訳すると、結構急いで作ったからすごい汚い。ループなんとかしたい。

#! /usr/bin/perl

### 格納リスト ###
@FILECHECK = ();
@NEWFILELIST = ();
@LASTFILELIST = ();
@TWONEWLIST = ();
@TWONLASTLIST = ();
@NEWCELLLIST = ();
@LASTCELLLIST = ();
@OUTPUT = ();
@OUTFIRSTPUT = ();

### 変数宣言 ###
$filecheck;
$newflag;
$lastflag;
$cnt;
$innewtmp;
$inlasttmp;
$newcnt;
$lastcnt;
$ReNewFileName;
$ReLastFileName;
$readnewline;
$readlastline;



# ファイル有無のチェック
@FILECHECK = glob("*");
# 配列要素の取得
$filecheck = @FILECHECK;


# 判定フラグ
$newflag = 0;
$lastflag = 0;

# エンコード
use Encode;
use utf8;


# ファイル分ループ
for(@FILECHECK){
    if($FILECHECK[$cnt] eq "newapfile"){
        $newflag = 1;
    }elsif($FILECHECK[$cnt] eq "lastapfile"){
        $lastflag = 1;
    }elsif($cnt==$filecheck-1 && $newflag==0){
        print "not there NewAPFile !!\n";
        exit;
    }elsif($cnt==$filecheck-1 && $lastflag==0){
        print "not there LastAPFile\n";
        exit;
    }elsif($cnt==$filecheck-1 && $newflag==1 && $lastflag==1){
        last;
    }$cnt++;
}
print "Let's APmatching start !!\n";


### csvファイル一覧取得 ###\
@NEWFILELIST = glob("newapfile/*.csv");
@LASTFILELIST = glob("lastapfile/*.csv");



### ファイルごとにループ ###
for($newcnt=0; $newcnt<scalar(@NEWFILELIST); $newcnt++){

    $ReNewFileName = 0;
    $ReNewFileName = $NEWFILELIST[$newcnt];
    $ReNewFileName =~ s/newapfile//g;

    for($lastcnt=0; $lastcnt<scalar(@LASTFILELIST); $lastcnt++){

        $ReLastFileName = 0;
        $ReLastFileName = $LASTFILELIST[$lastcnt];
        $ReLastFileName =~ s/lastapfile//g;

        if($ReNewFileName eq $ReLastFileName){

            print "matching $ReNewFileName\n";
            print "matching $ReLastFileName\n";
            print "Done..\n";

            @OUTPUT = ();
            @OUTFIRSTPUT = ();
            push(@OUTFIRSTPUT, $ReNewFileName);
            push(@OUTPUT, [@OUTFIRSTPUT]);

            
            # 二次元配列用
            @TWONEWLIST = ();
            @TWONLASTLIST = ();

            open INNEW, "<:encoding(shift-jis)", "$NEWFILELIST[$newcnt]" or die("could not open file.");
            open INLAST, "<:encoding(shift-jis)","$LASTFILELIST[$lastcnt]" or die("could not open file.");



            ### ファイルを1行ずつ読み込んで二次元配列に格納 ###

            $readnewline = 0;
            while(my $readnewline = <INNEW>){
                chomp $readnewline;
                @NEWCELLLIST = ();
                @NEWCELLLIST = split /\,/, encode("utf-8", $readnewline);
                push(@TWONEWLIST, [@NEWCELLLIST]);
                $i++;
            }
            close INNEW;

            $readlastline = 0;
            while(my $readlastline = <INLAST>){
                chomp $readlastline;
                @LASTCELLLIST = ();
                @LASTCELLLIST = split /\,/, encode("utf-8", $readlastline);
                push(@TWOLASTLIST, [@LASTCELLLIST]);
            }
            close INLAST;

            $i=0;
            $j=0;


            ### 突合処理 ###
            while($i<scalar(@TWOLASTLIST)){

                while($j<scalar(@TWONEWLIST)){
                    $k = 0;
                    $l = 0;
                    @OUTFIRSTPUT = ();

                    while($k<scalar(@{$TWOLASTLIST[$i]})){             
                        
                                        while($l<scalar(@{$TWONEWLIST[$j]})){

                            # エラー2のケース(数値)
                            if($TWOLASTLIST[$i][$k] =~ /^[0-9]+$/){
                                if($TWOLASTLIST[$i][$k] == $TWONEWLIST[$j][$l]){
                                    push(@OUTFIRSTPUT, "0,");
                                    $k++;
                                    $l++;
                                    last;
                                }else{
                                    push(@OUTFIRSTPUT, "1,");
                                    $k++;
                                    $l++;
                                    last;
                                }
                            }
                            # エラー2のケース(マイナスの場合)
                            elsif($TWOLASTLIST[$i][$k] =~ /-/){
                                if($TWOLASTLIST[$i][$k] == $TWONEWLIST[$j][$l]){
                                    push(@OUTFIRSTPUT, "0,");
                                    $k++;
                                    $l++;
                                    last;
                                }else{
                                    push(@OUTFIRSTPUT, "1,");
                                    $k++;
                                    $l++;
                                    last;
                                }
                            }
                            # エラー2のケース(空白の場合)
                            elsif($TWOLASTLIST[$i][$k] =~ /\s/){
                                if($TWOLASTLIST[$i][$k] == $TWONEWLIST[$j][$l]){
                                    push(@OUTFIRSTPUT, "ok null,");
                                    $k++;
                                    $l++;
                                    last;
                                }else{
                                    push(@OUTFIRSTPUT, "bad null,");
                                    $k++;
                                    $l++;
                                    last;
                                }   
                            }
                            # エラー1のケース(文字列)
                            else{
                                if($TWOLASTLIST[$i][$k] eq $TWONEWLIST[$j][$l]){
                                    push(@OUTFIRSTPUT, "True,");
                                    $k++;
                                    $l++;
                                    last;
                                }else{
                                    push(@OUTFIRSTPUT, "FALSE,");
                                    push(@OUTPUT, [@OUTFIRSTPUT]);
                                    @OUTFIRSTPUT = ();
                                    $j++;
                                    $k = 0;
                                    $l = 0;
                                    last;
                                }
                            }
                        }
                    }
                    push(@OUTPUT, [@OUTFIRSTPUT]);
                    $j++;
                    $i++;

                }
                $i++;
            }
            open OUT, ">APmatching_$newcnt.csv";
            for($m=0; $m<scalar(@OUTPUT); $m++){
                print OUT encode("UTF-8", "@{$OUTPUT[$m]}\n");
            }
            close OUT;
        }
    }
}

多次元配列へ配列をpushする場合

[@~]をpushする

@a = ([1,2,3], [4,5,6]);
@b = (7,8,9);
push(@a, [@b]);
foreach(@a){
    print"(@{$_})\n";
}

出力結果

1 2 3
4 5 6
7 8 9

多次元配列の要素となる配列を取り出す

普通に取り出すとARRAY(xxxxx)と配列そのものが表示されるため、@{$~}と書く。

@a = ( [1,2,3], [4,5,6] );

foreach ( @a ){
    print "( @{$_} )\n";
}

出力結果

1 2 3
4 5 6

ラベル

このコード上では使っていないけれど、ネストのループを回す際に出先をラベルによって指定することができる。 ※コードの一部分を抜粋

LAST1: while($i<scalar(@TWOLASTLIST)){

    NEW1: while($j<scalar(@TWONEWLIST)){
        $k = 0;
        $l = 0;
        @OUTFIRSTPUT = ();

        LAST2: while($k<scalar(@{$TWOLASTLIST[$i]})){                

            NEW2: while($l<scalar(@{$TWONEWLIST[$j]})){

            # エラー2のケース(数値)
            if($TWOLASTLIST[$i][$k] =~ /^[0-9]+$/){
                if($TWOLASTLIST[$i][$k] == $TWONEWLIST[$j][$l]){
                    push(@OUTFIRSTPUT, "0,");
                    $k++;
                    $l++;
                    last;
                }else{
                    push(@OUTFIRSTPUT, "1,");
                    $k++;
                    $l++;
                    last NEW1;  # NEW1の外側(=LAST1)まで抜ける
                }
            }
        }
    }
}

SIerはこの手のツール作るぐらいしかコード書く機会がないから辛い。

Remove all ads