Perlの文字コード変換の話 其の五

○ Encode::encode() / Encode::decode()


utf8フラグとPerlIOは、Perl 5.6 以降では超重要な概念となる。
PerlIO に文字エンコードが指定されていた場合、渡す文字列はutf8フラグが立っている
文字列が期待される。
逆に、文字エンコードが指定されていない場合、文字列にutf8フラグが立っていては
いけない。

場面に応じて、utf8フラグを立てたり、おろしたりする必要が出てくるわけだが、
これには、Encode::encode()とEncode::decode()を使う。

Encode::decode() は、バイト文字列(utf8フラグが降りている)文字列を、指定エンコード
読み込み、内部表現文字列を返す。

サンプルを次に示す。

use utf8;
use strict;
use warnings;
use Encode;
binmode( STDOUT, ':encoding(shiftjis)' );

my $a_data = "ほげほげ";
open( OUT, '>:encoding(shiftjis)', 'hoge_sjis.txt' );
print OUT $a_data;
close( OUT );

open( IN, '<:bytes', 'hoge_sjis.txt' ); my $a_sjis_str = ;
close( IN );

print "before : utf8 " . (Encode::is_utf8( $a_sjis_str ) ? "on" : "off") . "\n";

my $a_str = Encode::decode( 'shiftjis', $a_sjis_str );

print "after : utf8 " . (Encode::is_utf8( $a_str ) ? "on" : "off") . "\n";

Encode::encode() は、内部表現文字列を、指定エンコードのバイト列に変換する。
サンプルを次に示す。

use utf8;
use strict;
use warnings;
use Encode;
binmode( STDOUT, ':bytes' );


my $a_data = "ほげほげ";

print Encode::encode( 'shiftjis', $a_data ) . "\n";

ほげほげ

さて、ここで STDOUT の PerlIO を sjiftjis に指定した場合には、意図しない結果となる。

use utf8;
use strict;
use warnings;
use Encode;
binmode( STDOUT, ':encoding(shiftjis)' );


my $a_data = "ほげほげ";

print Encode::encode( 'shiftjis', $a_data ) . "\n";

"\x{0082}" does not map to shiftjis.
"\x{00d9}" does not map to shiftjis.
"\x{0082}" does not map to shiftjis.
"\x{0082}" does not map to shiftjis.
"\x{00d9}" does not map to shiftjis.
"\x{0082}" does not map to shiftjis.
\x{0082}\x{00d9}\x{0082}°\x{0082}\x{00d9}\x{0082}°

繰り返しになるが、PerlIOに文字エンコードが指定されていた場合、PerlIOに渡されるデータは
内部表現文字列であることが期待されている。
このため、Encode::encode() を用いてutf8フラグが落ちた文字列は、PerlIOに渡されても
期待通りの振る舞いにならない。

STDOUT を shiftjis に指定したから、shiftjisにエンコードして渡そうとするのは、大きな勘違い
である。