コンテンツにスキップ

CSVの文字化けを完全解決!文字コード・BOM・改行コードの基礎知識

カテゴリ:データ処理

CSVファイルを開いたら文字化けしていた、という経験は開発者なら誰しもあるのではないでしょうか。特に日本語を含むCSVは、文字コードの違いにより頻繁に問題が発生します。この記事では、文字化けの原因を根本から理解し、確実に解決するための知識をまとめます。

文字コードの基本:UTF-8 vs Shift_JIS

日本語の CSV ファイルで問題になる文字コードは、主に以下の2つです。

UTF-8

現在のWeb標準であり、世界中の文字を扱えるユニコードベースの文字コードです。Linux、macOS、モダンなWebアプリケーションではUTF-8がデフォルトです。1文字あたり1〜4バイトの可変長エンコーディングで、ASCII文字はそのまま1バイトで表現されます。

Shift_JIS(CP932)

WindowsのレガシーアプリケーションやExcelの旧バージョンで使われてきた日本語文字コードです。正確には、Windows環境では CP932(Microsoftによる Shift_JIS の拡張)が使われており、一部の機種依存文字(丸数字、ローマ数字など)はCP932でしか扱えません。

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

文字化けの根本的な原因は単純です。ファイルを書き出したときの文字コードと、読み込むときの文字コードが一致していないためです。

例えば、Webアプリケーションが UTF-8 で CSV をエクスポートし、ユーザーが Excel で開くと文字化けします。これは Excel が日本語環境ではデフォルトで Shift_JIS(CP932)としてファイルを解釈するためです。

BOM(Byte Order Mark)の役割

BOM とは、ファイルの先頭に付与される数バイトのマーカーで、文字コードを示す目印です。UTF-8 の BOM は 0xEF 0xBB 0xBF の3バイトです。

重要なポイントは、Excel で UTF-8 の CSV を正しく開くには BOM が必要ということです。BOM なしの UTF-8 CSV を Excel で開くと、Shift_JIS として解釈され文字化けします。

// PHP で BOM 付き UTF-8 CSV を出力する例
header('Content-Type: text/csv; charset=UTF-8');
header('Content-Disposition: attachment; filename="data.csv"');

// BOM を出力
echo "\xEF\xBB\xBF";

$fp = fopen('php://output', 'w');
fputcsv($fp, ['名前', 'メール', '部署']);
fputcsv($fp, ['田中太郎', 'tanaka@example.com', '開発部']);
fclose($fp);
# Python で BOM 付き UTF-8 CSV を出力する例
import csv

with open('data.csv', 'w', encoding='utf-8-sig', newline='') as f:
    writer = csv.writer(f)
    writer.writerow(['名前', 'メール', '部署'])
    writer.writerow(['田中太郎', 'tanaka@example.com', '開発部'])

ただし、BOM には注意点もあります。一部のプログラムやシェルスクリプトでは BOM を不正な文字として扱い、エラーの原因になることがあります。APIのレスポンスやプログラムで処理する CSV には BOM を付けない方が安全です。

改行コードの問題

CSVの文字化けと並んでよくある問題が改行コードの違いです。

  • CRLF\r\n)— Windows 標準
  • LF\n)— Linux / macOS 標準
  • CR\r)— 旧 Mac OS(現在はほぼ使われない)

RFC 4180 では、CSV の改行コードは CRLF と定められています。しかし実際には、多くのツールが LF のみの CSV も問題なく処理できます。問題が起きやすいのは、Excel や一部のレガシーシステムです。

改行コードの確認にはコマンドラインツールが便利です。

# file コマンドで確認
file data.csv
# 出力例: data.csv: UTF-8 Unicode (with BOM) text, with CRLF line terminators

# xxd で先頭バイトを確認(BOM の有無)
xxd data.csv | head -3

実践的な解決チャート

CSVの用途に応じた最適な設定を以下にまとめます。

用途 文字コード BOM 改行コード
Excel で開く UTF-8 あり CRLF
プログラムで処理 UTF-8 なし LF
レガシーシステム連携 Shift_JIS (CP932) なし CRLF
API レスポンス UTF-8 なし LF

テスト用CSVファイル

自分のアプリケーションがさまざまな文字コードのCSVを正しく処理できるか確認するには、DevLab のテスト用ファイルをお使いください。

まとめ

CSVの文字化け問題は、文字コード・BOM・改行コードの3つの要素を正しく理解すれば確実に解決できます。Excel向けにはBOM付きUTF-8でCRLF改行、プログラム処理にはBOMなしUTF-8でLF改行が基本です。DevLab の各種テストファイルを使って、自分のアプリケーションが各パターンを正しく処理できるか検証してみてください。

📚 関連記事

PNG vs WebP vs AVIF|画像フォーマットの選び方と変換方法

PNG / JPEG / WebP / AVIF の特徴・用途・ブラウザ対応状況を比較。picture 要素での出し分け、DevLab の画像フォーマット変換ツールの使い方も解説。

2026-04-18

Whois でドメイン情報を調べる方法|有効期限・ネームサーバー・登録者

Whois でわかること (登録者・有効期限・レジストラ・NS)、GDPR によるプライバシー保護の影響、ドメイン管理の実務的な使い方を解説。

2026-04-18

HTTP ステータスコード完全ガイド|よくあるエラーの原因と対処法

開発者が頻出する HTTP ステータスコード (200/301/302/400/401/403/404/413/422/429/500/502/503/504) の意味・原因・対処法を解説。301 vs 302 の SEO 影響、400 vs 422 の使い分けも。

2026-04-18

cURL コマンドを JavaScript fetch・Python requests に変換する方法|DevTools 連携

Chrome DevTools の Copy as cURL を fetch / axios / Python requests / PHP cURL / Go net/http に変換する手順を解説。主要 cURL オプション (-X / -H / -d / -F / -u / -b / -L) の変換パターン、認証トークンの扱い、注意点まで。

2026-04-16

Cookie のセキュリティフラグ完全ガイド|Secure / HttpOnly / SameSite / __Host-

Cookie のセキュリティ属性 Secure / HttpOnly / SameSite (Strict/Lax/None) / __Host- __Secure- プレフィックス / 4096 バイト制限を解説。CSRF / XSS / セッションハイジャック対策と、Laravel / Express の実装例。

2026-04-16

JWT のセキュリティベストプラクティス|alg none 攻撃 / 有効期限 / 署名検証

JWT (JSON Web Token) の代表的な脆弱性 6 種類 (alg none 攻撃 / 鍵混同 / 無期限トークン / payload への機密情報 / 失効不可 / 弱いシークレット) と対策。リフレッシュトークンパターン、失効リスト、HttpOnly Cookie 格納まで。

2026-04-16