今は保守っぽい仕事をやってるんですが、リリースのタイミングで更新のあったファイルだけをお客さんに送付することになっています。
そこで「ファイルの更新日時が特定の日時以降なら、そのファイルをコピーする」なんて Perl スクリプトを書いてます。
ところが、たまに「本番機の設定で送付しないといけないのに、開発機の設定のまま送付してしまう」なんてミスが起きてたので、NG-word 機能(ファイルに特定の文字 - 開発機の IP アドレスとか - が含まれていたら警告を表示する)を追加しました。
しばらくはちゃんと動作してたんですが、.xls や .png があると、警告が出まくることがわかりまして。
で、バイナリファイル検出方法で試行錯誤してたので、その対応の話。
とりあえず、最初にやった対策。
文字コードの判別に失敗したらバイナリファイルとみなす、というもの。
use Encode;
use Encode::Guess qw/euc-jp cp932 7bit-jis/;
my @files = <*>;
foreach my $file (@files) {
open IN, "<", $file or die "can't open $file: $!";
my $data = <IN>;
close IN;
my $enc = guess_encoding($data);
unless (ref($enc)) {
warn "no appropriate encoding\n";
next;
}
my $data = $enc->decode($data);
if ($data =~ /hoge/) {
warn qq/"hoge" found!\n/
}
}
(※実際は @files は File::Find 使ってますが、長くなるので省略)
でもこれだと .png が UTF-32BE として認識されて、チェックを抜けてしまうっぽく。
試しに
・
以前書いたアイテムと同じ方法で STDERR を取得
・エラーがあればバイナリファイルとみなす
なんて処理にしてみたんですが、これが結構重い。
ので、さらに別の方法。
if ($data =~ m/\p{Cn}/) {
warn "\p{Not_Assgined} found!\n";
next;
}
Unicode に該当しない文字がある場合はバイナリファイルとみなす、という処理。
普通に処理軽いし、今のところこの実装にしてます。
もっといい方法ご存知な方は教えてください・・・。
(2006/09/23 追記)
GIF ファイルが
・UTF-16BE
・UTF-16LE
・UTF-32BE
・UTF-32LE
あたりとみなさることがたまにあるっぽい。
鬱陶しいので guess_encoding() でこの辺りが出てきたらスキップすることに。
そうしてしまうとあまり意味ないような。
VSS6 は NULL があるかないかで判別してるらしいです。