合同会社小村ソフト
第 6 章

実務の落とし穴 — 宣言と実体を一致させる

文字化けの正体は「宣言(ラベル)」と「実体(バイト列)」の不一致。charset 宣言・Excel と BOM 付き UTF-8・改行コード・データベースの接続設定という現場の定番を片付ける。

「昨日まで正常だったのに」— 化けは境界で起きる

開発環境では正常なのに本番に上げたらページが化けた。バッチが出力した CSV を、利用者が Excel で開くと化ける。アプリからは正しく登録できているように見えるのに、DB を直接見ると別の文字が入っている。— 実務の文字化けは、たいていシステムとシステムの境界、つまりデータが手渡しされる場所で起きます。

この章の道具は 1 つだけです。境界を越えるデータには、実体(バイト列)と、それをどう読むべきかを伝える宣言(ラベル)がある。そして宣言はバイト列を変換してくれない。ただの札です。札と中身がズレた瞬間、受け取った側は間違った対応表を引き、第 1 章で見た文字化けが再生されます。

UTF-8 の実体に charset=Shift_JIS のラベルを付けて送ると、ブラウザがラベルを信じて誤読し文字化けする経路図

実体は UTF-8、ラベルは Shift_JIS。ブラウザはラベルを信じるので化けます。直すべきはラベルか、実体か — 両方の可能性を疑うのが調査の型です。

Web の宣言 — Content-Type と meta charset

Web ページの符号化のラベルは 2 か所にあります。HTTP 応答ヘッダの Content-Type: text/html; charset=UTF-8 と、HTML 内の <meta charset="UTF-8"> です。両方あるときは HTTP ヘッダが優先されます — サーバの設定が、ファイルに書かれた meta を上書きできるということです。

「ファイルは UTF-8 に変換したし meta も直したのに、本番だけ化ける」という怪現象は、たいていサーバやフレームワークが古い charset をヘッダに付けています。逆に、宣言がどこにもなければブラウザは推測で読みます。実体を UTF-8 にし、ヘッダと meta の両方を UTF-8 でそろえる — 現代の Web の基本形です。

Excel と CSV — 「BOM 付き UTF-8」が効く場面

CSV には charset ヘッダのような宣言の仕組みがありません。ダブルクリックで開かれたとき、従来の Excel は地域設定の既定(日本語環境なら CP932)として読みにいきます。UTF-8 で出力した CSV が化ける定番はこれです。

ここで第 3 章の BOM が活躍します。ファイル先頭に EF BB BF が付いていれば、Excel はそれを目印に UTF-8 として読んでくれます。「システムから出力する CSV は BOM 付き UTF-8 にする」は、Excel 利用者に開かれるファイルの定石です。ただし万能ではありません — BOM を想定していない別システムに同じファイルを渡すと、先頭 3 バイトが余計なデータとして誤動作を招くことがあります。誰が読むファイルかで、BOM の要否を決めるのが実務の判断です。

小問 6-1 — 宣言と実体

「ラベルはバイト列を変換しない」という原則を、Web と Excel の定番場面で確認します。

Q1. HTTP の Content-Type ヘッダの charset や HTML の meta charset の役割として正しいものはどれですか。

Q2. UTF-8 で保存された HTML が、charset=Shift_JIS と宣言されて配信され、文字化けしました。文字化けの「正体」の説明として最も正確なものはどれですか。

Q3. UTF-8(BOM なし)で出力した CSV を利用者がダブルクリックで Excel で開くと日本語が化ける、という定番トラブルがあります。ファイル側での代表的な対策はどれですか。

改行コード — もう 1 つの「見えないバイト」

符号化の相談を受けると、しばしば犯人は改行コードだった、ということがあります。改行もバイトです。Windows は CRLF(0D 0A)の 2 バイト、Unix/Linux・macOS は LF(0A)の 1 バイトが慣習で、同じ「見た目」のテキストでもバイト列が違います。

CRLF のファイルを LF 前提のプログラムに渡すと、各行の末尾に CR(0x0D)が残り、「値の末尾に見えない 1 文字が付いて比較が失敗する」「行数の数え方がずれる」といった、文字化けよりも気づきにくい不具合になります。CSV 連携の取り決めでは、符号化と改行コードをセットで指定する(例: UTF-8・BOM なし・LF)のが定石です。

データベース — 宣言は経路の全区間に必要

データベースにも符号化の設定は複数あります。代表的なのはテーブルや列の符号化(バイト列をどう格納・解釈するか)と、接続の符号化(アプリと DB の会話が何で行われるかの宣言)です。アプリ → 接続 → テーブルという経路のどこか 1 区間でも宣言と実体がズレると、格納時や取得時に誤変換・誤解釈が起き、化けたデータが保存されてしまいます。

厄介なのは、Web ページと違って化けた結果が永続化されることです。第 1 章の鉄則「化けたまま保存しない」の最悪形が、DB で静かに進行する化けデータの蓄積です。新規構築では最初に全区間を UTF-8 系でそろえる、既存システムでは「どの区間の設定が実体とズレているか」を 1 区間ずつ確かめる — 調査の型はここでも同じです。

この講座の合言葉、実務版: 化けたら「どの境界で、宣言と実体がズレたのか」。書いた符号化と読んだ符号化のズレは、境界の数だけ起きうる。

小問 6-2 — 見えないバイトと接続設定

改行コードとデータベース — 「見えない部分」の不一致を仕上げます。

Q4. 改行コードの説明として正しいものはどれですか。

Q5. データベースで文字化けが起きる典型的な原因として正しいものはどれですか。

Q6. 受け取ったテキストファイルの符号化を、読む前に 100% 確実に知る方法はあるでしょうか。

この章で持ち帰ること

  • charset はラベル。バイト列は変換されない。HTTP ヘッダは meta より優先される
  • Excel に開かれる CSV は BOM 付き UTF-8 が定石。ただし BOM の要否は「誰が読むか」で決める
  • 改行コード(CRLF 0D 0A / LF 0A)は符号化と別軸の「見えないバイト」問題。取り決めはセットで
  • DB はテーブルの符号化と接続の符号化の全区間一致が必要。化けの永続化が最悪パターン
  • 符号化を確実に判定する方法はない。仕様として決めて、宣言と実体を一致させるのが本丸

道具はすべてそろいました。最終章では、化けた画面そのものを証拠として、誤読の組み合わせを推理する総合演習です。