先日、GAE上のPHPを動作する上で、echo “あいうえお”が “BDFHJ”に文字化けして表示されました。
文字化けするのは文字コードが一致していない部分があるからなのですが、どうしてこのような英文字に変換されてしまうのか疑問に思ったわけです。
ブラウザのエンコードにあるUnicode(UTF-8)、日本語(シフトJIS)、日本語(EUC)、西ヨーロッパ言語(Windows)のいずれかでもない。
ネット上で「あいうえお BDFHJ」で検索するとそこそこヒットしたりします。
■調べてみた結果:
GAE上のPHPを動作させる「Quercus(クァーカス(クエルクス):ラテン語で「樫の木」の意味)」は、Javaで動作しています。Javaの文字列の内部コードはUnicode(UTF-16)となっております。(ちなみに.NETも文字列の内部コードもUnicode(UTF-16)ですね)
つまり、UTF-8で文字コードを設定しても、Javaの文字列内部コード上はUnicode(UTF-16)に変換されてしまうわけです。
区 | 点 | JIS | SJIS | EUC | UTF-8 | UTF-16 | 字 |
04 | 01 | 2421 | 829F | A4A1 | E38181 | 3041 | ぁ |
04 | 02 | 2422 | 82A0 | A4A2 | E38182 | 3042 | あ |
04 | 03 | 2423 | 82A1 | A4A3 | E38183 | 3043 | ぃ |
04 | 04 | 2424 | 82A2 | A4A4 | E38184 | 3044 | い |
04 | 05 | 2425 | 82A3 | A4A5 | E38185 | 3045 | ぅ |
04 | 06 | 2426 | 82A4 | A4A6 | E38186 | 3046 | う |
04 | 07 | 2427 | 82A5 | A4A7 | E38187 | 3047 | ぇ |
04 | 08 | 2428 | 82A6 | A4A8 | E38188 | 3048 | え |
04 | 09 | 2429 | 82A7 | A4A9 | E38189 | 3049 | ぉ |
04 | 10 | 242A | 82A8 | A4AA | E3818A | 304A | お |
Quercusは、既存のPHPアプリを動作させることを優先して文字セットは
ISO-8859-1(Latin-1)を前提としているようです。
http://www.atmarkit.co.jp/fjava/column/koyama/koyama05_2.htmlコンピュータは主にアメリカで発達してきたため、未だにアルファベットや数字などの1バイトを基本単位として扱う前提で作られており、日本語のように多くの文字を必要とする言語は、1文字を表わすのに2バイト以上を使います。
今回の文字化けの現象(あいうえお→BDFHJ)を見る限りは、2バイトではなく1バイトとして扱われてしまったことにあります。
あいうえお の文字コードと BDFHJ の文字コードを比較してみると、上位バイトの30が00と違っていても下位バイトは一致しています。
あいうえお | 3042 | 3044 | 3046 | 3048 | 304A |
BDFHJ | 0042 | 0044 | 0046 | 0048 | 004A |
それで、UTF-16からISO-8859-1の1バイト単位に変換されたならば上位バイトの30(文字:0)も変換されて、あいうえお→0B0D0F0H0J になるのでは? と思ったわけです。
そんなことを通勤途中の車の運転中に考えていたら、ふと思いついたんですよね。
「あいうえお」ではなく、echo “BDFHJ”と表示するようにしたとすると、文字列の内部コード上のUTF-16では00を上位バイトに付加したコード(例 B=0042)となります。
これを逆にUTF-16からISO-8859-1の1バイト単位に変換するとしたら、上位バイトは無視して下位バイトだけ取得すればいいわけです。
つまり、「あいうえお→BDFHJ」になるのは、UTF-16に変換後に下位バイトだけ取得して表示しているためです。
(実際は、下位バイトだけ取得後に所定の文字コード(例 UTF-8)に再変換されているはずです。今回は再変換されても表示が変わらなかった)
http://jfriends.javaopen.org/mlarchive_3/msg00135.htmlちなみに、Quercus3.1.6では上記の文字化けしなかったのですが、Quercus4.0以降では文字化けするようになってしまいます。
そんな対処法は下記サイトが参考になります。もっといい方法があるかも知れませんけどね。
QuercusでJavaからの日本語入力を取得して動作させる。
http://poepoemix.blogspot.com/2011/05/quercusjava.html