つづき。
以下のプログラムがあるとする。
#! perl
# noBinmode.pl -- decode して encode しないと怒られる
use strict;
use warnings;
use Encode;
my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $substr = substr($utf8, 5, 4);
print $substr;
__END__
実行してみる。(UTF-8 出力されるからリダイレクトで)
F:\Dropbox20091029\My Dropbox\Marugoto>noBinmode.pl > k.txt
Wide character in print at F:\Dropbox20091029\My Dropbox\Marugoto\noBinmode.pl line 12.
k.txt には正しく
ひらがな
と入っているが、「ワイド文字を print しました」と怒られる。
これは、既出だが、Perl 内部表現の文字列をオクテットストリームに変換しないでそのまま print したときのエラーである。
この場合は、binmode を使うか、Encode::decode_utf8() の逆関数 Encode::encode_utf8() を使う。
ここでは、encode_utf8(); を使ってみる。
#! perl
# expEncode.pl -- encode の実験
use strict;
use warnings;
use Encode;
my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $substr = encode_utf8(substr($utf8, 5, 4));
print $substr;
__END__
実行。
F:\Dropbox20091029\My Dropbox\Marugoto>expEncode.pl > k.txt
エラーが消えた。
無論、encode('UTF-8', ...) としても一緒である。
#! perl
# expEncode.pl -- encode の実験
use strict;
use warnings;
use Encode;
my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $substr = substr($utf8, 5, 4);
print encode("UTF-8", $substr);
__END__
今度はリダイレクトしないで実行してみると
F:\Dropbox20091029\My Dropbox\Marugoto>expEncode.pl
ゅ・繧峨′縺ェ
昔は文字化けというと魚偏だったけど、最近はこの糸偏が多い。
UTF-8 文字を強制的に Shift_JIS で解釈するとこのように怒られる。
ここで "UTF-8" を好みの文字コードに変えられる。
#! perl
# expEncode.pl -- encode の実験
use strict;
use warnings;
use Encode;
my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $substr = substr($utf8, 5, 4);
print encode("cp932", $substr);
__END__
F:\Dropbox20091029\My Dropbox\Marugoto>expEncode.pl
ひらがな
CP932 なので正しく DOS 窓に表示された。
★
さて、少し横道に逸れるが、現在スクリプトは UTF-8 になっているので、スクリプトに UTF-8 にはあるけれど、CP932 の文字レパートリーにない難しい字を書いた時にどうなるのかという問題がある。
#! perl
# expEncode.pl -- encode の実験
use strict;
use warnings;
use Encode;
#my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $utf8 = decode_utf8('abc漢字♠♥♦♣カタカナ');
my $substr = substr($utf8, 5, 4);
print encode("cp932", $substr);
__END__
いま、「ひらがな」の変わりに「♠♥♦♣」というトランプのマークを書いた。
これは、U+2660 らへんからある Unicode 文字である。

CP932 にあるかどうか知らない。
試みにこのスクリプトを秀丸で言うところの「日本語(Shift-JIS)」で保存してみる。
(IANA 登録名は Shift-JISではなくて Shift_JIS であり、実際には DOS 窓のコードページは CP932 だが)
次のように怒られる。

[はい] をクリックするとこうなる。

あららー。
元通り、♠♥♦♣に直して、UTF-8で保存しておく。

では実行する。
F:\Dropbox20091029\My Dropbox\Marugoto>expEncode.pl
????
? になって表示された。
これ、昨日 Dan Kogai さんじきじきに教わったのだが、encode に第3引数として 1 を渡せばよいという。
こうだ。
#! perl
# expEncode.pl -- encode の実験
use strict;
use warnings;
use Encode;
#my $utf8 = decode_utf8('abc漢字ひらがなカタカナ');
my $utf8 = decode_utf8('abc漢字♠♥♦♣カタカナ');
my $substr = substr($utf8, 5, 4);
print encode("cp932", $substr, 1);
__END__
実行する。
F:\Dropbox20091029\My Dropbox\Marugoto>expEncode.pl
"\x{2660}" does not map to cp932 at C:/strawberry/perl/lib/Encode.pm line 158.
あらホントだ~。
U+2660 は上に見たとおり確かにスペードである。
以下は参考ページ。
・http://blog.livedoor.jp/dankogai/archives/51047005.html
encode の第3引数については「まるごと」でも述べられており、よって本記事でも後述する。
★
ということで、基本はこう。
・処理の前に decode() -- オクテットストリームを Perl内部表現にする
・文字単位で処理
・処理の後に encode() -- Perl内部表現をオクテットストリームにする
「この基本を覚えておけば、Encodeの使い方はマスターしたも同然です。」(原記事より)
★
さて、また上の記事に戻るが、やはり CP932 でスクリプトを書きたい人は存在するだろう。
この場合は use utf8; の代わりに use encodings "cp932"; と書けるのだが、これは Dan さんによって強く非推奨されている。
・http://blog.livedoor.jp/dankogai/archives/50857509.html
・http://blog.livedoor.jp/dankogai/archives/51221731.html
表示の表やソ連のソの後半に \5c が入っていて、Perl は他にも @ とかいろいろぶつかるから、プログラムは EUC-JP で書いて入出力は nkf をかます、とか昔から言ってたのだが、今はプログラムは UTF-8 で書いて use utf8; し、外部からの入力は decode、外部への出力は encode するというのが正しいあり方のよう。
ただ、これに問題があるのが、Windows で使うプログラムを UTF-8 で書くと CP932 にない漢字(♠♥♦♣)を書いちゃうのではないか、ということなのだが、Dan さんによると、encode の第3引数に 1 を渡すと、croak してくれるという。
これは上でも見たがすごく便利。
でも、
・プログラムを書いた瞬間に怒られたい気がする
<=これは何らかのハックで、CP932 チェッカー的なものを保存時に走らせればいいだけかも。
Emacs とかだったらカンタンにできるのだが・・・。
・encode ではなくて binmode でできないだろうか?
<=とりあえず binmode に第3引数が「ない」ことは確かのよう。
これは今後の研究課題
今回は以上。
スポンサーサイト
まだalphaレベルですが、よろしければ試してみてください。
http://github.com/xaicron/p5-win32-unicode
P.S.
自分は深沢さんの著書、「すぐわかる オブジェクト指向 Perl」でPerlのオブジェクト指向を勉強しました。
今、Perlが好きで、毎日書いているのも、この本を読んだからだと思っています。
最高におもしろくて、わかりやすかったです。
どもども!
コメントはずいぶん前に把握してたんですが、さいきんマックを買ったもので、すっかりそっちに時間を取られてしまい、お返事を忘れてしまいました。
拙著がお役に立ち、あっという間に著者を追い抜いてりっぱなモジュールを開発されているようで望外の喜びです。
ぜひ使わせていただき、研究させていただきますのでよろしくお願いします。
今後もよろしく!
コメントの投稿