この日記の方針。
- この日記では、超初心者向けの内容は取り扱っておりません。モジュールの利用など、実践的な内容が中心となります。
- ここに貼られるソースは、基本的にそのままでは動かないものばかりです。各自の責任でご利用ください。
- 内容が間違っていることがあります。その際はご指摘いただけるとありがたいです。「検証してみたら違う結果が出た」などの報告も大歓迎です。
- perl -e die
2006-08-29 (Tue)どーなってんの日本語
■ [Encode] どーなってんのShift_JIS

昨晩、LWP::UserAgentでファイルを取得してArchive::Zipで固めるというCGIをリリース・・・しようとしたら、日本語の問題*1でつまづきました。
Shift_JISで書かれたファイルから1行ずつ読んでファイル名にしようとしてもうまく行かない。内部的な問題かと思い、Encode::from_to でUTF-8*2に変換して、ファイル名を作ってから再び戻すという処理をやってみたが、これもやはりうまく行かない。
ソースをShift_JISで書いていると「表示」を「表\示」とかやらないといけないのは有名な話だが。どうもそれとは違うらしい。0x5C*3 が入っていない文字列も、全部失敗している。
調べたところ、Encode::from_to でShift_JISに変換するところに問題があったらしい。
色々試したところ、UTF-8からShift_JISへの変換で、Encode::from_to($str, 'utf8', 'shiftjis', Encode::FB_HTMLCREF);では変換に失敗するけれど、$str = encode('shiftjis', decode('utf8', $str), Encode::FB_HTMLCREF);であれば、正しく変換(かつ、Shift_JISに無い文字はHTMLの数値文字参照に変換)されるようでした。 Encode::FB_HTMLCREFの変
この結果、こうなりました。
# 注:抜粋。単体では動きません。
while( my $line = <IN> ) {
next if( $line =~ /^\s*$/ ); # 空行無視してね。
Encode::from_to( $line, 'sjis', 'UTF-8' );
$line =~ s/[\r\n]//g;
my( $srcfile, $destfile ) = ( $line =~ /^([^\s\t]+)[\s\t]*(.*)$/ );
# destfileに拡張子を付ける。
my( $ext ) = ( $srcfile =~ /\.([^\.]*)$/ );
$destfile = sprintf( '%s.%s', $destfile, $ext )
if( $destfile !~ /\.$ext$/ );
# Encode::from_to( $destfile, 'UTF-8', 'sjis' );
$destfile = Encode::encode('shift_jis', Encode::decode('utf8', $destfile), Encode::FB_HTMLCREF);
push( @$list, { src => $srcfile, dest => $destfile || $srcfile } );
}
難しいことはわかりません。でも動いたのでOKです*4。
で、完成したCGIって?
Sky RiverというMIDI音楽サイト(個人)の一括ダウンロードの管理画面になりました。本館のリンクのページからどうぞ。
どうでも良いんだけど
use Encode;
ってやると、暗黙の了解で Encode::JP も読み込まれるらしい。
わけわからん。
追記
これ、変でした。
$destfile = Encode::encode('shift_jis', Encode::decode('utf8', $destfile), Encode::FB_HTMLCREF);
第3引数要りません。HTML用にエスケープされちゃったら大変。
もうひとつ。こっちはArchive::Zipの問題かどうか不明なのだが。
Windowsエクスプローラで開くと化けます。化けた文字は・・・「十」。すなわち、2バイト目が 0x5C!どーしたらいいものやら。
コメント
トラックバック - http://perl.g.hatena.ne.jp/Cress/20060829