本文へスキップ
AZ Tools

文字が化けて変な記号になる理由

ディスクの上に、ただのテキストというものは存在しません。ファイルにあるのはバイトで、文字コードとは、どのバイトあるいはバイトの組がどの文字を表すかという取り決めです。ふつうのテキストファイルはその取り決めを記録していないので、開くプログラムはすべて推測をしています。推測が外れると文字化けが起き、その化け方は何が起きたかを知る確かな手がかりになります。

文字化けには覚えておく価値のある特徴がある

いちばん見慣れているのは、一文字が二文字に増える化け方です。UTF-8では é は C3 と A9 の二バイトで保存されますが、そのファイルを西欧のコードページで一バイトずつ読むプログラムは、それを Ã と © として表示します。UTF-8のファイルを古い一バイト文字コードで読むと、英語以外の文字はすべてこの調子で二文字か三文字になり、それが連なった結果が、日本語や韓国語のテキストがラテン文字の瓦礫の壁に見える理由です。

ほかの三つの印は意味が違います。ファイルが  で始まるなら、バイト順マーク付きのUTF-8を別のものとして読んでいます。疑問符の入った黒い菱形は置換文字で、指定された文字コードでは成立しえないバイトに出くわしたときにデコーダーが書き込む記号です。文字があるはずの場所にただの疑問符があるなら、たいていはその文字を収める場所のない文字コードへ変換されたということです。

そのうち二つは、すでに文字が失われた印

é は取り戻せます。元のバイトはファイルにそのまま残っていて、解釈だけが間違っているからです。同じバイトを正しい文字コードで読めば、テキストはそっくり戻ります。

置換文字とむき出しの疑問符は違います。それが今そのファイルに入っている中身そのものです。元のバイトは変換した瞬間に捨てられていて、その菱形が é だったのか ü だったのかは、あとのどんな工程でも分かりません。文字コードの不具合を直すときの第一の掟が、そのファイルに上書き保存するのをやめることだ、というのはこのためです。誤った文字コードで保存するたびに、戻せる問題が戻せない問題に変わります。

二重変換と、それが繰り返される理由

あるプログラムがUTF-8を一バイト文字コードとして読み、その結果をUTF-8として保存すると、間違いは取り返しがつかないように見える形になります。ファイルにはいまや Ã と © という文字が本当に入っていて、それぞれが自分の二バイトを占めています。二回起きれば一文字が四文字になり、次は八文字です。

それでも元に戻せます。何回起きたかさえ分かれば、工程をそのまま逆にたどれるからです。回数の分だけ、一バイトのコードページへ符号化し直してからUTF-8として読み解けばよいのです。この形がこれほどよく現れるのは、たいていパイプラインの中で起きるからです。フォーム、データベースの列、書き出しといった段階で、すでに一度変換を通ったデータに同じ変換がもう一度かかります。

いまも出会う古い文字コード

西欧のテキストはたいていWindows-1252で届きます。人がLatin-1と言うとき、実際に指しているのはたいていこれです。この違いは重要で、Windows-1252はLatin-1が空けている領域を、丸い引用符やダッシュ、三点リーダーで埋めています。気の利いた引用符がしばしば “ として現れるのはそのためです。古い東アジアのシステムから来たテキストはShift_JIS、EUC-KR、Big5、GB18030で、キリル文字はWindows-1251やKOI8-Rでやってきます。

職場でいちばんよくある出どころは表計算です。WindowsでCSVを書き出すと、いまだにUTF-8ではなくシステムのコードページで書かれがちなので、作った機械の上では完璧に見えるファイルが、ほかのあらゆる場所で化けます。しかも同じ機械で開き直すと問題なく見えるため、作った本人にはその不具合が見えません。

判定は推測であり、短い文字列ではさらに当てにならない

UTF-8は自分自身を検証します。複数バイトの並びが厳密な規則に従うので、UTF-8としてきれいに読み解けるファイルは、ほぼ確実にUTF-8です。判定器が自信をもって出せる答えはこれひとつです。

いっぽう一バイトの文字コードは、どんなバイトでも成立してしまうので、どれも除外できません。判定器は、実際の言語でどの文字や文字の組み合わせがよく出るかを見て選びます。この方法は段落なら通用し、名前ひとつや列の見出しでは失敗します。二十バイトの文字列に対して、確信度は低いがWindows-1252だと答える道具は、不親切なのではなく正直なのです。

ファイルが自分を名乗ることになっている場所

宣言を持てる形式は、はるかに扱いやすくなります。HTMLにはmeta charsetがあり、XMLには宣言があり、HTTPで送られるものはContent-Typeヘッダーに文字コードを書けます。そしてこのヘッダーは、文書が自分について述べていることより優先されるので、文書が正しくてもヘッダーが間違っていれば結局化けます。

UTF-8ファイルの先頭に置かれるバイト順マークも一種の宣言で、これは諸刃の剣です。理解する編集ソフトからは推測をなくしてくれますが、理解しない道具は壊します。位置ゼロで予期しない文字だと訴えるJSONパーサー、一行目がもうシバンでなくなったシェルスクリプト、最初の列名に見えない文字がくっついたCSVなどがその例です。

化けたファイルを実際に直す手順

画面ではなくバイトから始めてください。ファイルを十六進で開き、アクセント付きの文字が一バイトで入っているのか二バイトなのかを見ます。それだけで、古い文字コードのファイルなのか、UTF-8を読み違えているのかが分かれます。次に候補の文字コードで読み解いてみて、本物の単語が戻るかを確かめます。判断の基準は、結果が変わったかどうかではなく、テキストが正しいかどうかです。

読めるようになったら、写しをUTF-8で保存し、確信が持てるまで原本には触れないでください。そして直す場所は途中ではなく境界です。データが入るときに読み解き、内部では文字コードをひとつに揃え、出ていくときにそれを宣言します。同じ問題を繰り返す相手はたいてい途中で変換しているパイプラインで、ひとつの間違いが二度かかる経路がまさにそれです。

関連ツール