← PC・IT用語集へ戻る

BOM(バイトオーダーマーク)

Byte Order Mark
data development beginner
ファイルの先頭に置かれ、文字コードの種類やバイトの並び順を示す数バイトの目印。
BOM(バイトオーダーマーク) (Byte Order Mark)

概要(サマリー)

BOM(バイトオーダーマーク)とは、テキストファイルの先頭に置かれる、文字コードの種類やバイトの並び順を示す数バイトの目印である。

役割は「このファイルはこの文字コードで書かれています」という宣言に近い。ファイルを開くソフトはこの数バイトを見て、どの文字コードとして読めばよいかを判断できる。

やっかいなのは、この目印が画面には表示されないことである。そのため「見た目は正常なのに、プログラムで読むと1行目だけおかしい」「Excelでは開けるのにシステムに取り込めない」といった、原因の分かりにくいトラブルを引き起こす。日本語のCSVを扱うと、ほぼ必ず一度は遭遇する。

詳細解説

BOMとは何か(見えない3バイト)

BOMの正体は、Unicodeのコードポイント U+FEFF である。この文字は「ゼロ幅ノーブレークスペース」と呼ばれ、幅を持たないため画面には何も表示されない。

これをファイル先頭に置くと、符号化方式によって次のようなバイト列になる。

  • UTF-8: EF BB BF(3バイト)
  • UTF-16 リトルエンディアン: FF FE(2バイト)
  • UTF-16 ビッグエンディアン: FE FF(2バイト)

ソフトはこの先頭数バイトを見るだけで、文字コードを推測できる。テキストエディタで「UTF-8」と「UTF-8 BOM付き」が別項目になっているのは、この3バイトを付けるかどうかの違いである。

なぜBOMが生まれたのか(バイト順の問題)

そもそもBOMは、UTF-16のために作られた仕組みである。

UTF-16では1文字を2バイトで表すが、その2バイトをどちらの順番で並べるかは、コンピュータの設計によって異なる。先に大きい桁を置く方式をビッグエンディアン、先に小さい桁を置く方式をリトルエンディアンと呼ぶ。

順番を取り違えると、文字はまったく別のものになってしまう。そこで「先頭に U+FEFF を置き、それがどう並んで見えるかで判断させる」という発想が生まれた。これがバイトオーダーマーク(バイト順の目印)という名前の由来である。

一方UTF-8は1バイト単位で処理するため、本来バイト順の問題は存在しない。それでもUTF-8にBOMを付ける習慣が生まれたのは、バイト順を示すためではなく、「このファイルはUTF-8である」と宣言する目印として流用されたからである。

ExcelとCSVをめぐる有名な問題

現場で最もBOMが問題になるのが、日本語CSVをExcelで開く場面である。

Windows版のExcelは、CSVをダブルクリックで開いたとき、BOMがないと文字コードを環境依存の方式(従来はShift_JIS系)だと推測する。そのため、UTF-8のBOMなしCSVを開くと日本語が文字化けする。

逆にBOMを付けておけば、ExcelはUTF-8だと正しく判断し、文字化けせずに開ける。つまりExcel利用者向けのCSVでは、BOMは付けたほうが親切である。

しかし、そのBOM付きCSVをプログラムで読むと、今度は別の問題が起きる。

// BOM付きUTF-8のCSVをそのまま読むと、
// 1列目のヘッダーに見えない3バイトが混入する
const header = lines[0].split(",")[0];
console.log(header);          // 見た目は "名前"
console.log(header === "名前"); // false ← 一致しない

ヘッダー名で列を判定している処理は、これで静かに壊れる。エラーにならず「なぜか1列目だけ取得できない」という形で現れるため、原因にたどり着きにくい。

プログラム側でBOMを取り除く

読み込み側で対処する場合は、先頭の U+FEFF を除去する。

JavaScriptでは次のように書ける。

// 先頭にBOMがあれば取り除く
function stripBom(text) {
  return text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;
}

Pythonでは、読み込み時の符号化方式に utf-8-sig を指定すると自動的に処理される。

# utf-8-sig はBOMがあれば取り除き、なければそのまま読む
with open("data.csv", encoding="utf-8-sig") as f:
    text = f.read()

utf-8 ではなく utf-8-sig を使うのが定石である。BOMの有無が混在するファイルを扱う場合でも安全に動く。

BOMは付けるべきか、付けないべきか

正解は用途によって変わる。判断の目安は次のとおりである。

  • 付けたほうがよい: Excelで開くことを前提にした日本語CSVを配布する場合
  • 付けないほうがよい: ソースコード、設定ファイル、HTML、Webサーバーが配信するファイル

ソースコードにBOMが付くと、言語や環境によっては構文エラーになったり、PHPで「Headers already sent」の原因になったり、シェルスクリプトの1行目の指定が壊れたりする。開発用のファイルは原則BOMなしと覚えておけばよい。

すでに文字化けしてしまったファイルを受け取った場合は、元の文字コードを推定して読み直すことで復元できることがある。

AIコーディングとの関係

AIにCSVの入出力処理を書かせるとき、BOMは明示的に伝えないと考慮されないことが多い。「動くはずのコードなのに1列目だけ取れない」という相談の多くはこれが原因である。

出力側は、次のように用途を伝えると適切な実装になりやすい。

日本語のCSVをダウンロードさせる処理を書いてください。
利用者がWindows版Excelで開く前提なので、UTF-8にBOMを付けてください。

読み込み側は、逆にBOMを許容するよう指示する。

アップロードされたCSVを読み込む処理を書いてください。
BOM付きUTF-8とBOMなしUTF-8のどちらでも、
1列目のヘッダー名が正しく取得できるようにしてください。

AIが生成したコードをテストするときは、BOM付きとBOMなしの両方のファイルで確認することが重要である。片方だけのテストでは、この不具合は表面化しない。

よくある勘違い

BOMが付いていても見た目は変わらないから無害?

無害ではない。画面に表示されないだけで、実データとしては3バイト存在する。文字列比較、ヘッダー名の判定、JSONのパースなどで静かに失敗する原因になり、しかもエラーメッセージが出ないため発見が遅れやすい。

UTF-8には必ずBOMを付けるべき?

そうではない。UTF-8はバイト順の問題がないため、BOMは本来不要である。Excel対策として付ける場面はあるが、ソースコードや設定ファイルに付けると不具合の原因になる。用途に応じて使い分けるものである。

BOMを付ければ文字化けは必ず防げる?

防げるとは限らない。BOMはあくまで目印であり、読み込む側がそれを解釈してくれる場合にだけ有効である。BOMを無視するプログラムもあるし、そもそもファイルの中身が別の文字コードで書かれていれば、BOMがあっても正しくは読めない。

BOMはブラウザのBOM(Browser Object Model)と同じ?

まったく別物である。この項目で扱うBOMはByte Order Markであり、文字コードの目印である。JavaScriptwindowdocument を扱う際に出てくるBrowser Object Modelとは無関係なので、文脈で読み分ける必要がある。

まとめ

  • BOMは、ファイル先頭に置かれ文字コードやバイト順を示す、画面に表示されない数バイトの目印である
  • UTF-8のBOMは EF BB BF の3バイトで、本来はバイト順ではなく「UTF-8である」という宣言として使われる
  • Windows版ExcelでCSVを開く場合、BOMがないと日本語が文字化けする
  • 一方でプログラムから読むとヘッダー名に混入し、エラーにならないまま処理が壊れることがある
  • Excel向けCSVには付け、ソースコードや設定ファイルには付けない、という使い分けが基本である

情報ソース

より詳しくAIに聞いてみよう

  • BOM付きUTF-8とBOMなしUTF-8の違いを、実際のバイト列を示しながら説明してください。
  • 日本語CSVをExcelで文字化けさせずに開かせる方法を、サーバー側の実装込みで教えてください。
  • BOMが原因で起こる不具合の代表例と、その見分け方を教えてください。
  • アップロードされたCSVがBOM付きかどうかを判定する処理を書いてください。
  • ソースコードにBOMが混入した場合に起こる問題を、言語ごとに整理してください。