unzipで展開されるファイル名が化けないようにする その2

前回のエントリを書いた後でここのShift JIS対応パッチを見つけた。内容を見るとだいたい自分が次にやろうとしていたことと同じだったが、使ってみると少し問題があった。このパッチでは文字コードの変換にiconvを使っているのだが、iconvは変換できない文字を見つけるとそこで処理を中止してしまうので、丸付き文字等の機種依存文字があるとそれ以降のファイル名が失われてしまう。iconvを機種依存文字に対応させるパッチもあるが、iconvはglibcの一部なのでパッチを当てるのは抵抗がある。他にcp932に対応した有名な文字コード変換ライブラリも知らないので、結局前回と同様にunzipでは文字コード変換は一切せずにファイル名を変換するスクリプトと併用することに落ち着いた。やはり文字コード変換はスクリプトでやった方が簡単だし色々融通を利かせやすい。

以下適当に作ったファイル名変換用スクリプト。なお、ソースをちょっと弄るとフィルタとしても使用できる。

(2006/9/10 3:23 修正)

#!/usr/bin/perl

use strict;
use warnings;

use Jcode;

my %cp932 = (
    "\x87\x40" => '(1)',
    "\x87\x41" => '(2)',
    "\x87\x42" => '(3)',
    "\x87\x43" => '(4)',
    "\x87\x44" => '(5)',
    "\x87\x45" => '(6)',
    "\x87\x46" => '(7)',
    "\x87\x47" => '(8)',
    "\x87\x48" => '(9)',
    "\x87\x49" => '(10)',
    "\x87\x4a" => '(11)',
    "\x87\x4b" => '(12)',
    "\x87\x4c" => '(13)',
    "\x87\x4d" => '(14)',
    "\x87\x4e" => '(15)',
    "\x87\x4f" => '(16)',
    "\x87\x50" => '(17)',
    "\x87\x51" => '(18)',
    "\x87\x52" => '(19)',
    "\x87\x53" => '(20)',

    "\x87\x54" => 'I',
    "\x87\x55" => 'II',
    "\x87\x56" => 'III',
    "\x87\x57" => 'IV',
    "\x87\x58" => 'V',
    "\x87\x59" => 'VI',
    "\x87\x5a" => 'VII',
    "\x87\x5b" => 'VIII',
    "\x87\x5c" => 'IX',
    "\x87\x5d" => 'X',
    "\x87\x5f" => 'ミリ',
    "\x87\x60" => 'キロ',
    "\x87\x61" => 'センチ',
    "\x87\x62" => 'メートル',
    "\x87\x63" => 'グラム',
    "\x87\x64" => 'トン',
    "\x87\x65" => 'アール',
    "\x87\x66" => 'ヘクタール',
    "\x87\x67" => 'リットル',
    "\x87\x68" => 'ワット',
    "\x87\x69" => 'カロリー',
    "\x87\x6a" => 'ドル',
    "\x87\x6b" => 'セント',
    "\x87\x6c" => 'パーセント',
    "\x87\x6d" => 'ミリバール',
    "\x87\x6e" => 'ページ',
    "\x87\x6f" => 'mm',
    "\x87\x70" => 'cm',
    "\x87\x71" => 'km',
    "\x87\x72" => 'mg',
    "\x87\x73" => 'kg',
    "\x87\x70" => 'cc',
    "\x87\x7e" => '平成',
    "\x87\x82" => 'No.',
    "\x87\x83" => 'K.K.',
    "\x87\x84" => 'TEL',
    "\x87\x85" => '(上)',
    "\x87\x86" => '(中)',
    "\x87\x87" => '(下)',
    "\x87\x88" => '(左)',
    "\x87\x89" => '(右)',
    "\x87\x8a" => '(株)',
    "\x87\x8b" => '(有)',
    "\x87\x8c" => '(代)',
    "\x87\x8d" => '明治',
    "\x87\x8e" => '大正',
    "\x87\x8f" => '昭和',
    "\x87\x91" => '≡',
    "\x87\x92" => '∫',
    "\x87\x93" => '§',
    "\x87\x94" => 'Σ',
    "\x87\x95" => '√',
    "\x87\x96" => '⊥',
    "\x87\x97" => '∠',
    # "\x87\x98" => '',
    # "\x87\x99" => '',
    "\x87\x9a" => '∵',
    "\x87\x9b" => '∩',
    "\x87\x9c" => '∪',

    "\xfa\x40" => 'i',
    "\xfa\x41" => 'ii',
    "\xfa\x42" => 'iii',
    "\xfa\x43" => 'iv',
    "\xfa\x44" => 'v',
    "\xfa\x45" => 'vi',
    "\xfa\x46" => 'vii',
    "\xfa\x47" => 'viii',
    "\xfa\x48" => 'ix',
    "\xfa\x49" => 'x',
    "\xfa\x4a" => 'I',
    "\xfa\x4b" => 'II',
    "\xfa\x4c" => 'III',
    "\xfa\x4d" => 'IV',
    "\xfa\x4e" => 'V',
    "\xfa\x4f" => 'VI',
    "\xfa\x50" => 'VII',
    "\xfa\x51" => 'VIII',
    "\xfa\x52" => 'IX',
    "\xfa\x53" => 'X',
    "\xfa\x58" => '(株)',
    "\xfa\x59" => 'No.',
    "\xfa\x5a" => 'TEL',
    );

my %tr = map { (Jcode->new($_, 'sjis')->euc, $cp932{$_}) } keys %cp932;
my $pat = join('|', keys %tr);

#my $sjis_re = '[\x81-\x9F\xE0-\xFC][\x40-\x7E\x80-\xFC]';
my $euc_re = '[\x8E\xA1-\xFE][\xA1-\xFE]|\x8F[\xA1-\xFE][\xA1-\xFE]';

sub proc {
    local $_ = Jcode->new(shift, 'sjis')->euc;
    s/($pat)|($euc_re)/defined $1 ? $tr{$1} : $2/ego;
    return $_;
}

sub filter {
    while (<>) {
        print &proc($_);
    }
}

sub main {
    foreach my $f (@ARGV) {
        my $from = $f;
        my $to = &proc($f);
        rename $from, $to if $from ne $to;
    }
}

#&filter;
&main;

追記。しまった、どうせJcode使ってるならJcode::CP932を使えば良かった。
参考:404 Blog Not Found:perl - Jcode の EUC-JP