文字化けはなぜ起きる?UTF-8とUTF-16の違いや『推測で読めそう』に見える理由をわかりやすく解説

C言語関連

文字化けは『保存した文字コード(エンコード)』と『読み込む側が想定した文字コード』が一致していない時に発生します。例えばUTF-8で保存されたファイルをShift_JISやUTF-16として読み込むと、本来とは違う文字として解釈され、意味不明な文字列になることがあります。

特にUTF-8とUTF-16はどちらもUnicode系の文字コードなので、『バイト列から推測できそう』と感じる人も多いですが、実際には単純な話ではありません。

文字コードとは『数字と文字の対応ルール』

コンピュータ内部では文字もすべて数値として保存されています。例えば『A』という文字はUnicodeではU+0041という番号で管理されています。

ただし、その番号を実際にどういうバイト列に変換して保存するかは、エンコード方式ごとに異なります。

文字コード 特徴
UTF-8 可変長。英数字は1バイト、日本語は3バイト程度
UTF-16 基本2バイト単位。文字によって4バイトになる場合もある
Shift_JIS 日本語Windowsで長く使われた形式

つまり、同じ『あ』という文字でも、UTF-8とUTF-16では保存されるバイト列が違います。

UTF-8をUTF-16として読むとどうなるのか

例えばUTF-8で保存されたデータを、読み込む側が『これはUTF-16だ』と誤認すると、2バイト単位や4バイト単位で無理やり解釈しようとします。

すると、本来は別々の意味だったバイトがまとめて解釈され、全然違うUnicode番号になってしまいます。

質問にある『前半が全部0なら推測できるのでは?』という考え方は一部正しいです。実際、ASCII文字だけならUTF-16では上位バイトが0になることがあります。

例えば英字Aは次のようになります。

UTF-8:41UTF-16:00 41

この場合は推測しやすいですが、日本語や絵文字になると事情がかなり複雑になります。

なぜ自動判定が難しいのか

文字コード判定ソフトは『この並びならUTF-8っぽい』『これはShift_JISらしい』という統計的推測をしています。しかし、完全には判定できません。

例えば次の問題があります。

  • 同じバイト列が複数の文字コードで成立する
  • 短い文章だと特徴が少ない
  • 日本語と英語が混在すると判定が難しい
  • 偶然UTF-8にもShift_JISにも見える場合がある

そのため、文字コードは『絶対に自動判定できる』わけではありません。

UTF-8とUTF-16は単純な8bit対16bitではない

よく誤解されますが、UTF-8は『常に8bit』、UTF-16は『常に16bit』という意味ではありません。

UTF-8は可変長エンコードで、文字によって1〜4バイト使います。UTF-16も文字によっては4バイト必要です。

例えば『あ』は以下のようになります。

UTF-8:E3 81 82UTF-16:30 42

このように、UTF-8とUTF-16ではデータ構造自体が異なるため、『前半に0を付ければ変換できる』という単純なものではありません。

BOM(バイトオーダーマーク)で判定する場合もある

UTF-16やUTF-8では、ファイル先頭にBOMという識別情報を付ける場合があります。

形式 BOM例
UTF-8 EF BB BF
UTF-16 LE FF FE
UTF-16 BE FE FF

これがあると『このファイルはUTF-16ですよ』と判断しやすくなります。

ただし、BOMが無いファイルも多く、その場合はアプリ側が推測するしかありません。

文字化けが起きる代表例

実際には以下のような場面で文字化けが起きやすいです。

  • WindowsのShift_JISファイルをLinuxでUTF-8として開く
  • CSVをExcelで開いた時に文字コードが違う
  • Webサーバーのcharset設定ミス
  • データベース保存時のエンコード不一致

特に日本語環境ではShift_JISとUTF-8の混在が昔から多く、現在でもトラブルの原因になります。

まとめ

文字化けは、単純に『8bitを16bitで読んだから』というだけではなく、『どのバイト列をどの規則で文字として解釈するか』のズレによって発生します。

ASCII文字だけなら推測可能な場合もありますが、日本語や絵文字ではUTF-8とUTF-16の構造差が大きいため、完全自動判定は難しいのが実情です。

そのため、ファイル保存時と読み込み時で同じエンコードを使うことが、文字化け防止の基本になります。

コメント

タイトルとURLをコピーしました