仕事で使える(かもしれない)Perlコード (固定長ファイル編)

固定長ファイルのxバイト目からnバイトでソートする

(my($x, $n) = @ARGV) || die "parameter expected.";
sub by_char {
    $a1 = substr($a, $x, $n); $b1 = substr($b, $x, $n); return $a1 cmp $b1;
}
@lines = <STDIN>;
@sorted = sort by_char @lines;
foreach (@sorted){ print; }

固定長ファイルのxバイト目からnバイトがtargetに等しい行を出力する

(my($x, $n, $target) = @ARGV) || die "parameter expected.";
while(<STDIN>){ if(substr($_, $x, $n) eq $target){ print; } }

固定長ファイルのxバイト目からnバイトの値と出現回数を集計する

(my($x, $n) = @ARGV) || die "parameter expected.";
while(<STDIN>){
    $a = substr($_, $x, $n); $arr{$a}++;
}
foreach (keys(%arr)){
    print $_ . "\t" . $arr{$_} . "\n";
}

固定長ファイルの各行の先頭n文字を固定の文字に置き換える
これは簡単なので「ワンライナー」でやってみましょう。 下の例では、固定長っぽいテキストファイルの全ての行の先頭3文字を、 「ABC」に置き換えてfixed.datに上書きします。 元のファイルは.BAKをつけてfixed.dat.BAKに退避されます。
なお、ワンライナーでは、文末にセミコロンは不要です。

perl -i.BAK -pe "$_ = 'ABC' . substr($_, 3)" fixed.dat


仕事で使える(かもしれない)Perlコード (タブ区切りファイル編)

タブ区切りの2ファイルの各行各列の値を比較し、差異があれば出力する

($infile1, $infile2) = @ARGV;
$infile2 || die "usage: coldiff.pl file1 file2";

sub readFile {
    my($fileName) = @_; open(INFILE, $fileName) || die $!;
    my(@data) = <INFILE>; close(INFILE); return @data;
}

@data1 = &readFile($infile1);
@data2 = &readFile($infile2);

$lineno = 1;
foreach (@data1){
    $line1 = $_;
    chomp($line1);
    $line2 = shift(@data2);
    chomp($line2);
    exit if (! $line1) || (! $line2);
    @rowdata1 = split(/\t/, $line1);
    @rowdata2 = split(/\t/, $line2);
    $x = 1;
    foreach (@rowdata1){
        $data1 = $_;
        $data2 = shift(@rowdata2);
        if($data1 ne $data2){
            print "${lineno}行目\t${x}列目の値は違います:\t[$data1]\t[$data2]\n";
        }
        $x++;
    }
    $lineno++;
}

タブ区切りのテキストファイルを読み、行のnフィールド目が前の行と同じであれば、その行は省いて出力する

my($field) = shift(@ARGV) || die "usage: uniqfield.pl {fieldIndex} {fileNames}";
my($prev) = "aaa"; # 対象フィールドの値としてとりえない文字列を設定すること
while(<>){
    chomp; $line = $_; @arr = split;
    if($arr[$field] ne $prev){
        print $line . "\n";
        $prev = $arr[$field];
    }
}

コマンドラインで指定する$fieldは、0から開始です。

タブ区切りのデータを、HTMLのTABLE形式に変換する その1
これはWebアプリケーションの画面サンプルを作りたいときやなんかに使います。 そのままだと本当に簡単なので、 各行にチェックボックスや入力欄も追加するサンプルにしてみました。 なお、全体を囲むtableタグは省略しています。

while(<>){
    print "<tr>\n";
    @a = split(/\t/, $_);
    foreach $td (@a){
        print "<td>$td</td>";
    }
    print <<AAA;
<td><input type="checkbox"/></td><td><input type="text" size="12"/></td>
</tr>
AAA
}

タブ区切りのデータを、HTMLのTABLE形式に変換する その2
これも同じですが、行末の列に空フィールドが含まれていると、 chompしたり引数なしでsplitしたりすると消えてしまうので、 その防止策を入れています。 また、最初の行は見出し行(th要素)にする、 特定の列には右詰(text-align:right)のスタイルを入れる、 などの追加を行っています。

$first = 1;
while(<>){
    @a = split(/\t/);
    print "<tr>";
    $col = 0;
    foreach (@a){
        s/[\r\n]//g;
        if($first){
            print "<th>" . $_ . "</th>";
        } elsif($col == 4 || $col == 6 || $col == 7) {
            print "<td style='text-align:right'>" . $_ . "</td>";
        } else {
            print "<td>" . $_ . "</td>";
        }
        $col++;
    }
    print "</tr>\n";
    if($first){
        $first = 0;
    }
}


仕事で使える(かもしれない)Perlコード (ファイル変換編)

aaa.sh ⇒ AAA.sh 一括変換
カレントディレクトリにある.shファイルの主ファイル名を、全て大文字に変換します。

@files = <*.sh>;
foreach (@files){
    $newname = $oldname = $_;
    $newname =~ "(.+)\.sh";
    $mainname = $1;
    $mainname =~ tr/[a-z]/[A-Z]/;
    $newname = $mainname . ".sh";
    print "$oldname ==> $newname\n";
    rename($oldname, $newname) || die $!;
}

ファイル内の特定のパターンの変換
awkっぽい処理ですね。 テキストファイル内にある "AAA=bbb"という行を、"AAA=BBB" に置き換えて出力します。

perl -i.orig conv.pl *.sh
のようにすれば、複数のファイルを一括して変換できます。

while(<>){
    if ($_ =~ /AAA=(.+)/) {
        $a = $1;  $a =~ tr/a-z/A-Z/;  $_ =~ s/$1/$a/;
    }
    print;
}


仕事で使える(かもしれない)Perlコード (その他のファイル操作)

ある拡張子のファイルを数える
「Perlの覚え書きメモ」で触れた、「再帰的にディレクトリを検索するサンプル」 の拡張です。 コマンドラインで(基点ディレクトリ、拡張子)を受け取り、 基点ディレクトリ以下を再帰的に検索し、 拡張子を含むファイルの一覧と最後にファイル数を数えて出力します。

  • 拡張子は.をつけて指定する必要はありません。
  • 名前が合致すれば、ディレクトリやリンクも数える対象になります。

(my($basedir, $ext) = @ARGV) || die "parameter expected.\n";

sub showdir {
    my($indir, $ext) = @_;
    opendir(INDIR, $indir) || die "opening $indir:" . $!;
    my(@files) = readdir(INDIR);
    closedir(INDIR);

    foreach (@files){
        if($_ ne '.' && $_ ne '..'){
            $path = $indir . "/" . $_;

            if($path =~ /\.${ext}$/){
                print $path . "\n";
                $count++;
            }

            if(-d $path){
                & showdir($path, $ext);
            }
        }
    }
}

$count = 0;
& showdir($basedir, $ext);
print $count . "\n";

Misc. Topics Top

(first uploaded 2005/10/09 last updated 2011/05/08, URANO398)

テレワークならECナビ Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!
無料ホームページ 無料のクレジットカード 海外格安航空券 海外旅行保険が無料! 海外ホテル