文字化けはなぜ起きる?文字コード(UTF-8・Shift_JIS)とBOMの基礎

別の環境で開いたファイルが、画面いっぱいに「縺ゅ◇縺・」のような呪文を並べていた。

そんな文字化けに、私は何度ぎょっとさせられたか分かりません。

中身は壊れていないのに、文字だけが知らない言語に化けてしまう。

その犯人は、ふだん意識しない文字コードのすれ違いです。

この記事では、文字化けがなぜ起きるのかを、バイトと文字の関係からほどいていきます。

文字コードは「バイトと文字」の対応表

コンピュータが扱えるのは、突き詰めれば 0 と 1 が並んだバイトの列だけです。

その数値の並びを「この番号はこの文字」と決めた約束ごとが、文字コードと呼ばれるもの。

たとえば同じ「あ」でも、どの約束ごとを使うかで割り当てられるバイトが変わります。

# 同じ「あ」でも文字コードで割り当てが変わる
>>> "あ".encode("utf-8")
b'\\xe3\\x81\\x82'   # UTF-8 では 3 バイト
>>> "あ".encode("shift_jis")
b'\\x82\\xa0'       # Shift_JIS では 2 バイト

つまり保存するときと読むときで違う約束ごとを使えば、当然ながら別の文字に化ける。

代表的な文字コードの違い

日本語を扱う現場では、長らく複数の文字コードが併存してきました。

いまの標準は UTF-8

現在のWeb・アプリ開発で事実上の標準になっているのが UTF-8 です。

1文字を1〜4バイトの可変長で表し、世界中の文字を一つの体系で扱えるのが強み。

しかも先頭の128文字はASCIIとバイト単位で互換なので、英数字だけの設定ファイルはそのまま読めます。

まだ出会う Shift_JIS

一方、古いWindows環境や既存システムでは Shift_JIS がいまも残っています。

同じ「あ」を2バイトで表すなど、UTF-8 とはバイトの並びがまったく違う。

新規に選ぶ理由はほぼありませんが、受け取ったファイルが Shift_JIS だった、という遭遇は今も起こります。

なぜ文字化けは起きるのか

文字化けの正体は、ほとんどが「保存した約束ごと」と「読んだ約束ごと」のズレです。

UTF-8 で保存したファイルを Shift_JIS だと思い込んで開けば、バイトの解釈がずれて別の文字に化ける。

# 読み込み時は encoding を必ず明示する
with open("memo.txt", encoding="utf-8") as f:
    text = f.read()
# encoding を省くと OS のデフォルトに依存し、化けの温床になる

やっかいなのは、ファイル自身が「私は何コードです」と名乗ってくれないこと。

だから読む側が正しいコードを指定するか、正しく推測してやる必要があります。

BOM という小さな目印

この「名乗らない」問題への、ささやかな目印が BOM(Byte Order Mark)です。

UTF-8 の BOM は、ファイル先頭に置かれる EF BB BF という3バイト。

「このファイルは UTF-8 です」という署名として働きます(W3Cの解説)。

ただし便利な反面、シェルスクリプトやJSONでは余計な一文字として悪さをすることもある。

つけるか外すかは、扱うツールが BOM をどう解釈するかで決めるのが安全です。

文字化けを防ぐ習慣

仕組みが分かれば、対策は驚くほど単純になります。

  • 迷ったらUTF-8 に統一する:新規ファイルは理由がない限り UTF-8(BOMなし)で保存する
  • エンコーディングを明示する:読み書きを環境のデフォルト任せにしない
  • 文字コード表示を確認する:エディタで開いた瞬間に何コードかを見る癖をつける

改行コードと同じで、人の注意力ではなく設定やコードに約束を肩代わりさせるのが結局いちばん楽。

改行コードCR・LF・CRLFの違いと仕組み

改行コードも同じ「見えない制御の世界」の話なので、あわせて読むと腑に落ちると思います。

最後に

文字化けは、一見すると不気味な現象に見えます。

けれど正体は「保存と読み取りで約束ごとがずれた」だけの、とても素直なすれ違い。

UTF-8 への統一と、エンコーディングの明示。この2つを習慣にするだけで、あの呪文に悩まされる回数はぐっと減ります。

以上です。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA