Encode.pm 最近の雑感

2.19 から ISO-2022-JP の encode() が custom fallback に対応(CHECK をきちんと CHECK するようになった)とのことでめでたい。miyagawa ++

で,どこ変わったの?とみてみたら,

@@ -49,7 +49,7 @@
     # empty the input string in the stack so perlio is ok
     $_[1] = '' if $chk;
     my ( $h2z, $jis0212 ) = @$obj{qw(h2z jis0212)};
-    my $octet = Encode::encode( 'euc-jp', $utf8, FB_PERLQQ );
+    my $octet = Encode::encode( 'euc-jp', $utf8, $chk );
     $h2z and &Encode::JP::H2Z::h2z( \$octet );
     euc_jis( \$octet, $jis0212 );
     return $octet;

あ,やっぱそこっすか。実は Encode::EUCJPMS の CP50220 / CP50221 も流用してるんで,こちらは未だに必ず PERLQQ になってしまう罠。RT にあげたほうがいいかな。

んで,Encode の encode() って渡した文字列が侵食されうるんですよね。Encode::LEAVE_SRC を渡すと侵食しないんですが(ちなみに FB_PERLQQ と FB_HTMLCREF と FB_XMLCREF には LEAVE_SRC フラグが含まれてます),custom fallback function だとそのような意図を伝えることができないのが残念。

実際,

use Encode;

my $s1 = $s2 = 'A①';

my $d1 = encode('EUC-JP',      $s1, FB_DEFAULT);   # $s1 は侵食されない
   $d1 = encode('EUC-JP',      $s1, sub { '!' });  # $s1 は侵食されない

my $d2 = encode('ISO-2022-JP', $s2, FB_DEFAULT);   # $s2 は侵食されない
   $d2 = encode('ISO-2022-JP', $s2, sub { '!' });  # $s2 は侵食される!(空になる)

のように,エンコーディングによって挙動が違うんですよね。仕様といえば仕様のようですが。