読者です 読者をやめる 読者になる 読者になる

Perl日記

PerlとかRubyとかPHPとかPythonとか

decode(utf8=>$str)とdecode_utf8($str)のちがい

昨日のエントリで文字化けした件についてもう少し調べてみた。
Devel::Peekで文字化けした文字をダンプしたところ、面白いことがわかった。
UTF-8フラグがついていない文字列のはずなのに、FLAGSの欄に"UTF8"が出ていた。

  FLAGS = (PADMY,POK,pPOK,UTF8) # <=これ

ていうか、そもそもそれ(UTF8フラグ)付いてたら、例えdecode(utf8=>$str)でもコケるんじゃね?と思ったのだが、どうやらそうでない場合もあるようだ。
具体的にはASCII文字列をdecodeしたものにencodeされた文字列をくっつけると、UTF8と判定されてしまうようである。

$ cat dump.pl
use Devel::Peek;
use Encode;

use utf8;
no utf8;
{
  my $w = "テスト".decode_utf8("2012");
  Dump($w);
  Dump(decode(utf8=>$w));
  Dump(decode_utf8($w));
}
$ perl5.14.2 dump.pl
SV = PV(0xa10c120) at 0xa11eb68
  REFCNT = 1
  FLAGS = (PADMY,POK,pPOK,UTF8)
  PV = 0xa156528 "\303\243\302\203\302\206\303\243\302\202\302\271\303\243\302\203\302\2102012"\0 [UTF8 "\x{e3}\x{83}\x{86}\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{88}2012"]
  CUR = 22
  LEN = 24
SV = PV(0xa10c150) at 0xa10e068
  REFCNT = 1
  FLAGS = (TEMP,POK,pPOK,UTF8)
  PV = 0xa124790 "\343\203\206\343\202\271\343\203\2102012"\0 [UTF8 "\x{30c6}\x{30b9}\x{30c8}2012"]
  CUR = 13
  LEN = 16
SV = PV(0xa10c150) at 0xa10e068
  REFCNT = 1
  FLAGS = (TEMP,POK,pPOK,UTF8)
  PV = 0xa128b40 "\303\243\302\203\302\206\303\243\302\202\302\271\303\243\302\203\302\2102012"\0 [UTF8 "\x{e3}\x{83}\x{86}\x{e3}\x{82}\x{b9}\x{e3}\x{83}\x{88}2012"]
  CUR = 22
  LEN = 24

3つダンプされたので、「Cannot decode string with wide characters」で死んでいない。
そしてオリジナルとdecode_utf8()の文字列が同じであるということが分かる。
decode_utf8()は何も変更していない文字列を返却している。


対してdecode(utf8=>$str)の方は確かにdecodeされた文字列を返している。





ひとまず、「decode_utf8で文字化けし、decode(utf8=>$str)で文字化けしなかったのか?」という解は得られた。
「文字列の一部分であるASCIIがdecodeされた文字列をdecode_utf8()に渡しても何もしないが、decode(utf8=>$str)は強制的に(?)変換しているから」である。

というかそんな中途半端な状態の文字列を作るな、渡すな、という話ではあることは、十分理解していますw