Skip to main content

ログ取得ツール (移転先予定地)

文字コードの謎

HTML中に、「自」という数値文字参照があるとしよう。これがなぜかUnicodeの「0xE8 0x87 0xAA」の3バイトになってしまう、という話。(ちなみに「自」という字です)

この変換をしてしまうのは、 perl -X -pe ’s/&#([0-9]*);/sprintf("%c", $1);/ge;’ という、数値文字参照を解決しようとした1-lineのフィルタだ。

10進数の33258は、16進数にすると、当然0x81eaである。これは「0xE887AA」とは似ても似つかない。そして、「自」の文字はEUC:0xBCAB、JIS:0x3C2B、SJIS:0x8EA9であって、同じ2バイトの0x81EAにはつながらないのだ。ちなみに0x81EAをUnicodeとして認識しようとしてもダメなのである。

こんな変てこりんなことになったのはこの人(mac.com)のせいである。この人のページはHTMLもRSSも、タグ以外の日本語文字が全部数値文字参照になっているという強烈な特性を持っているのである。中身は悪くないのだが…。たぶん、英語のソフトを無理矢理日本語で使っているのだろうな。

実は、情けないことにまだ解決してない。謎は続く。

(追記) 2003-09-11 17:50

実はPythonやPHPやawkで同じような書き方をしても「自(自)」を「自(0xE887AA)」に変換することはできない。Perlが偉いのだが、ただなぜ正しく動作してしまうのかが謎なのだ。

(追記) 2003-09-11 21:40

iconvで調べたところ、0x81eaが「自」である文字コードは、WCHAR_T、UCS-2BE(Big Endian?)、UCS-4など、Unicode系である。Perlは内部でUCS-2で管理しているために%cの引数がUCS-2になっていて、出力のときにUTF-8に変換しているのだろうか??

(追記) 2003-09-12 11:53

Cのprintfの場合、l修飾子をつけると(%lcとか%lsとか)ワイドキャラクタ系の引数として扱われる。perlは%cが%lcなんだろうな、たぶん。とりあえずこれで納得したことにする。

(追記) 2003-09-17 10:33

Pythonではフォーマット文字列をUnicodeにしとくといいみたい。

unicode("%c") %(33258) => u’\u81ea’ (unicode("%c") %(33258)).encode(“japanese.euc_jp”) => ‘自’