TIM Labs

化けて出た文字幽霊の正体を探る

| コメント(1) | トラックバック(0)

ここ最近文字コードはUTF-8で統一することが多くなったので、 いわゆる「文字化け」を目にすることは随分少なくなったが、 それでもまだ「化けて出る」のが日本語という奴ではある。

で、まあ文字コード関連のノウハウは色々あるようだけども、 今回はそういう話題ではない。

この幽霊たち、いくつかは特徴のある姿をしているので、 分かりやすい幽霊についてちょっと紹介してみようと思う。

糸偏幽霊

これは最近良く見るようになった幽霊だ。なにやら糸偏のついた漢字が多く混じっている。

縺薙l縺ッUTF-8縺ョ繝・く繧ケ繝医〒縺吶よ怙霑代・谿・←縺薙l縺ァ縺吶・縲

サンプルの文字列には正体を埋め込んであるのでバレバレではあるが、 こいつはUTF-8であるにも関わらず、 CP932(あるいはShift_JIS、色々細かい話はあるがとりあえず今回は気にしないことにする)で 解釈されてしまったがための幽霊である。

というわけで、元のバイナリ列がそのまま保持されているのなら、 UTF-8として再解釈してあげればちゃんと読めるようになる。

元々の文字列はこうだ:

これはUTF-8のテキストです。最近は殆どこれですね。

が、なんらかの伝送路を通じてこれが送られてきた場合、 例えば「こんなん表示されたんだけど...」とかってコピー&ペーストされてきた場合は、 一部のデータが欠落しているので、残念ながら完全に元に戻すことはできない。 でも、やってみると思いのほか復元できたりするので、結構面白い。

ちょっとやってみよう。 端末設定はUTF-8を想定する。コマンドラインは適当に改行しているので了解してほしい。本来は一行だ。

% echo '縺薙l縺ッUTF-8縺ョ繝・く繧ケ繝医〒縺吶よ怙霑代・谿・←縺薙l縺ァ縺吶・縲' |
  iconv -c -f utf-8 -t cp932

これはUTF-8のチE??ストです?最近?E?E??これです?E?

なんとなく元の文字列が見えた。 内容によってはかなり綺麗に復元できたりする。

混乱しがちなのだが、iconvが出力しているのは指示の通りcp932である。 しかし、端末がUTF-8の設定になっているので、cp932バイナリ列をUTF-8で解釈して表示している。 ということは、間違いなく「化けた」文字列なのだが(まあ確かに半分化けている)、 元々UTF-8だった文字列をCP932に「間違って解釈していた」ので、 そいつが剥がれて意味を成している部分が見える、というわけだ。

半角カナ幽霊

こいつも結構特徴のある幽霊だ。見たことがある人も多いだろう。

、ウ、・マeuc-jp、ホ・ニ・ュ・ケ・ネ、ヌ、ケ。」、ス、・ハ、熙ヒハリヘタ、テ、ソ、ホ、ヌ、゙、タクォ、ォ、ア、゙、ケ。」

なにやら半角カナがたくさん見える。

ま、こちらも正体はバレバレなのだが、euc-jpがcp932として解釈されて出た幽霊だ。 というわけでもちろん、元のバイナリがあればeuc-jpで再解釈してやればちゃんと読める:

これはeuc-jpのテキストです。それなりに便利だったのでまだ見かけます。

伝送路を通した後の場合を想定して、これもちょっと救出に挑戦してみよう。

% echo '、ウ、・マeuc-jp、ホ・ニ・ュ・ケ・ネ、ヌ、ケ。」、ス、・ハ、熙ヒハリヘタ、テ、ソ、ホ、ヌ、゙、タクォ、ォ、ア、゙、ケ。」' |
  iconv -c -f utf-8 -t cp932 | iconv -c -f euc-jp -t utf-8

こEeuc-jpのテキストです。そE覆蠅吠慷だったのでまだ見かけます。

うむ。なんとか読めなくはない。

まあ半角カナは伝送路で全角文字に変換されてしまう危険があるのが悩ましいところではあるが。

iconvを二回使っているが、これは端末設定がUTF-8であることを想定しているためだ。 よくパイプの繋ぎを見てみると、一回目のiconvはcp932を出力しているにも関わらず、 二回目のiconvはeuc-jpを入力としている。 この繋ぎ目で「元々あった勘違い」を正しているというわけだ。

半角記号幽霊

いやはや、こいつは実に分かりやすい幽霊だ。

B$3$l$O(Jiso-2022-jp$B$N%F%-%9%H$G$9!#(JJIS$B$H$b8@$C$?$j$7$^$9!#EE;R%a!<%k$G$O8=Lr$G$9!#

正体が含まれていなくてもバレバレだね。当然iso-2022-jpである。

これはiso-2022-jpのテキストです。JISとも言ったりします。電子メールでは現役です。

如何せん7bit encodeなので、UTF-8で解釈しようがEUCで解釈しようがcp932で解釈しようが全て同じ化け方をする。 おかしなことになるのは、文字集合切替時のエスケープシーケンスの部分だけである。 上記例では完全にエスケープシーケンス部分はドロップされているが、 場合によっては変な記号が見えているかもしれない。

さて、同じように伝送路上でエスケープシーケンスが失われていると仮定しよう。 その場合、切替シーケンスの "\x1B$B" と "\x1B(J" を再現してやればいいことになる。 つまり、"$B" の前と、 "(J" の前に、エスケープシーケンス "\x1B" を単純に追加してやれば、 大抵の場合は上手くいく。

やってみよう。

% echo '$B$3$l$O(Jiso-2022-jp$B$N%F%-%9%H$G$9!#(JJIS$B$H$b8@$C$?$j$7$^$9!#EE;R%a!<%k$G$O8=Lr$G$9!#' |
  sed -e `echo -en "s/\\$B/\033\\$B/g"` | sed -e `echo -en "s/(J/\033(J/g"` |
  iconv -f iso-2022-jp -t utf-8

これはiso-2022-jpのテキストです。JISとも言ったりします。電子メールでは現役です。

完全に復元できた。さすが7bit。

まあもちろん、本物の "$B" や "(J" が本文中に含まれていたりするとおかしなことになる可能性はあるが、 それでも細々と対応してあげれば元の文章は復元できるハズだ。

ラテン式幽霊

こんな幽霊もたまに見かける。

?±?ê?ÍCP932?Ì?e?L?X?g?Å??BShift-JIS?Æ?Ì×?©?¢??Ù?Í?C?É???Ü???ñB
¤?¤ì¤Ïeuc-jp¤Î?Æ?????ȤǤ?¡£¤?¤ì¤Ê¤ê¤ËÊØÍø¤À¤Ã¤¿¤Î¤Ç¤Þ¤À¸?¤?¤±¤Þ¤?¡£
ã"ã?Œã¯UTF-8ã®ã?†ã??ã??ã??ã§ã™ã??æœ?è¿'ã¯æ®†ã©ã"ã?Œã§ã™ã?ã?

日本人の目にはどれもこれも似たように映るので、正直正体がなんなのかは分かりづらい。 いくつか特徴的な記号を含んではいるので、慣れればなんとか見分けはつきそうではあるが。

サンプルのテキストはこれまでと同じなので、良く見れば一応わかるが、正体は上から各行 cp932、euc-jp、UTF-8 である。

これはCP932のテキストです。Shift-JISとの細かい差異は気にしません。
これはeuc-jpのテキストです。それなりに便利だったのでまだ見かけます。
これはUTF-8のテキストです。最近は殆どこれですね。

で、何に間違えられたのかといえばもちろんiso-8859-1、別名Latin-1である。

これまでと同じ方法で救出を試みてみよう。

% echo '?±?ê?ÍCP932?Ì?e?L?X?g?Å??BShift-JIS?Æ?Ì×?©?¢??Ù?Í?C?É???Ü???ñB' |
  iconv -c -f utf-8 -t iso-8859-1 | iconv -c -f cp932 -t utf-8

アヘCP932フeLXgナキBShift-JISニフラゥ「キルヘCノオワケ


% echo '¤?¤ì¤Ïeuc-jp¤Î?Æ?????ȤǤ?¡£¤?¤ì¤Ê¤ê¤ËÊØÍø¤À¤Ã¤¿¤Î¤Ç¤Þ ¤À¸?¤?¤±¤Þ¤?>>¡£' |
  iconv -c -f utf-8 -t iso-8859-1 | iconv -c -f euc-jp -t utf-8

これはeuc-jpのテキストです。それなりに便利だったのでまだ見かけます。


% echo 'ã"ã?Œã¯UTF-8ã®ã?†ã??ã??ã??ã§ã™ã??æœ?è¿'ã¯æ®†ã©ã"ã?Œã§ã™ã?ã?' |
  iconv -c -f utf-8 -t iso-8859-1

???UTF-8???????????????????

大変残念なことに、euc-jp以外は絶望的だ。が、逆に言うとeuc-jpがほぼ完璧に復活するのは面白い。

...と思ったが、本blogに記述したものをコピー&ペーストして再実行したところ、

?れはeuc-jpの??????箸任?。?れなりに便利だったのでま だ??けま?>>。

なんて結果になったので、伝送路によっては色々欠落があるようだ。cp932の結果もblogからコピーだと若干結果が違うようだし、最後のUTF-8はblogからのコピーだと実行すらできない。残念だ。が、まあこの辺は色々仕方あるまい。

その他の幽霊

その他の幽霊は、大変残念なことに「?」やら「□」やらの羅列で殆ど判別がつかない上に、 複数の文字が同じ文字に変換されてしまう以上救うことも殆ど不可能だ。 かろうじてアルファベット部分は読めることもあるが、 それがどのくらい役に立つかは場合によりけりである。

まぁ普通文字化けしたところで、元々の文章が日本語だってことが分かっているなら、 大抵2-3種類のエンコード解釈を試してあげればちゃんと表示されるので、 読む分にはそんなに困ることもないのではあるが。

ま、一番困るのは、同じ文書内に複数のエンコードが混じってるときかな...。 なんでそんなことになるんだよ...と言いたいところだが、 それなりにあったりするのが現実の厳しいところである。

トラックバック(0)

トラックバックURL: http://labs.timedia.co.jp/mt/mt-tb.cgi/115

コメント(1)

めちゃくちゃ参考になりました。
文字化けでは苦しんでいるひとが多いと思うのですけど
ここまでいろいろ研究している方は初めて見ました。
私はまさに「iso-8859-1」への誤変換で悩んでいました。こちらのページの情報がとっかかりで解決しました!
本来UTF8なのにiso-8859-1になってしまっている、ということがわかったのが大きかったです。
ありがとうございました!

コメントする

このブログ記事について

このページは、1024が2010年12月17日 13:32に書いたブログ記事です。

ひとつ前のブログ記事は「Javaで高階関数」です。

次のブログ記事は「Javaでアキュムレーター」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。