Perl 5.6 以降では、文字列に Unicode フラグというのがつきます。
XML など文字コードを明示的に指定した場合などは Unicode 文字列として扱われ、length などが文字セマンティクスで動作します。
ある変数に Unicode フラグがたっているかどうかは、Devel::Peek モジュールでわかります。
use Devel::Peek;
Dump $s
ここで問題になるのが、文字列連結での自動アップグレード問題といわれるもので、内部的に Unicode フラグがたっている文字列と、そうでない文字列を連結すると、自動的にそうでないほうが Unicode にアップグレードされます。ここが文字化けの原因になります。
1. テンプレートを UTF-8 で記述し、Template-Toolkit で読み込み
2. DB は MySQL に UTF-8 に格納して DBD::mysql で取り出し
3. ローカルの RSS ファイルを XML::RSS でパースして取り出し
とやってつなげると、すべて UTF-8 なバイト列なのですが、3. だけに Unicode フラグがたちます。最後に結合するときに1. と 2. が自動アップグレードされて化けます。
5.8 であればファイルハンドルに binmode とかやったりして適切に Unicode フラグたてられますが 5.6 ではそうもいきません。またこの例のように、TT や DBI など、モジュール内部で文字列が作られていじれない場合もあります。
というわけでこういうときは 3. から UTF-8 フラグを外してやるのがてっとりばやいです。
5.8 では use utf8; utf8::downgrade($s);
、5.6 では pack('C*', unpack 'C*', $s);
のようにすればとりあえずフラグは外れます。
Jcode.pmのインターフェースを持った
Encode.pmのラッパーを書いていたのですが、
trがうまく動作せずに悩んでいました。
この記事のおかげでDevel::Peekを使って
確認すればいいことを知り、解決しました。
ありがとうございます。