AIに売上表や一覧をCSVで作らせ、Excelで開くと日本語が読めない文字になることがあります。Microsoftは、BOMという目印付きで保存したUTF-8(=いま標準の文字の保存形式)のCSVなら通常どおり開けると案内しています。目印が無いファイルは、1行のコマンドで付けるか、Excelの[データ]から取り込めば開けます。
この記事で分かることは次のとおりです。
- 文字化けしたCSVの調べ方
- 手元のファイルにBOMを付ける方法
- AIへの具体的な頼み方
- 異なるCSVを壊さずに結合する方法
ZEN AI LABでは2026-09-19にCodexとClaude CodeでCSVを作り、ファイルの先頭を調べました。BOMの追加とCSV結合も実ファイルで検証しています。読み終えたら、手元のsales.csvを調べて修正できます。
化けたらまず先頭3バイトを見る
CSVが文字化けしていても、中の文字まで失われたとは限りません。文字コード(=文字を保存するときの決まり)と、開く側の読み方が合っているかを切り分けます。BOMは、ファイルの先頭に付く、UTF-8で書かれていることを示す目印です。

ZEN AI LABのテストでAIが作った14ファイルは、すべてUTF-8として正しく読めました。化けて見えても、中身の文字は残っていました。後述のBOMを付けるPythonの1行がエラーなく終われば、そのファイルはUTF-8として読めています。先頭3バイトを見るコマンドでは、UTF-8かどうかまでは分かりません。
確認は次の順番で進めます。
- 化けた画面のまま上書き保存せずに閉じます。
- 元のファイルをコピーしておきます。
- CSVのあるフォルダでコマンドを実行し、先頭3バイト(=ファイルのいちばん最初の3つの値)を見ます。
EF BB BFならBOMあり、E5 95 86のように別の値ならBOMなしです。
Pythonで先頭を見る
sales.csvは自分のファイル名に置き換えます。このコマンドはPythonが入っているPCで動きます。Pythonが無い場合は、後述するPowerShellのFormat-Hexで見られます。
python -c "print(open('sales.csv','rb').read(3).hex(' ').upper())"
BOMありの実出力はEF BB BFでした。BOMなしで最初の文字が「商」の実出力はE5 95 86でした。16進数は、ファイル内のバイトを短い記号で表したものです。
PowerShellでは次を実行します。
Format-Hex -Path sales.csv
00000000で始まる行の、最初の3つの値を見ます。EF BB BFならBOMがあります。
Microsoftのサポートページは、BOM付きのUTF-8のCSVなら通常どおり開けると案内しています(2026-09-19確認)。
化けた文字の例(Pythonで再現)
次はPythonによるシミュレーションです。Excelの画面を再現したものではありません。BOMなしのUTF-8をcp932(Windowsで使われるShift_JIS)として読み、読めない部分を�に置き換えました。
| 元の見出し | cp932として読んだ表示 |
|---|---|
| 商品名,売上金額,販売日 | 蝠�蜩∝錐,螢イ荳企≡鬘�,雋ゥ螢イ譌・ |
| 日付,商品名,数量,単価,売上金額 | 譌・莉�,蝠�蜩∝錐,謨ー驥�,蜊倅セ。,螢イ荳企≡鬘� |
BOMを1行のコマンドで付ければ開ける
先頭がEF BB BFではなく、UTF-8として読めるファイルにはBOMを付けられます。上書きするため、次の順番を守ってください。
- 元のファイルをコピーします。
- CSVのあるフォルダで次のコマンドを実行します。
python -c "p='sales.csv';s=open(p,encoding='utf-8-sig',newline='').read();open(p,'w',encoding='utf-8-sig',newline='').write(s)"
- もう一度、先頭3バイトを見るコマンドを実行し、
EF BB BFを確かめます。 - Excelでファイルを開きます。
ZEN AI LABでは、BOMなしのUTF-8ファイルに実行しました。ファイルは134バイトから137バイトになり、先頭がEF BB BFに変わりました。同じコマンドをもう1回実行してもBOMは1つのままで、改行(LF)と本文は元と同じでした。
utf-8-sigは、BOMを扱うためのPythonの指定です。Pythonの公式ドキュメントによると、書き込み時にはUTF-8のBOMを先頭に付け、読み込み時には先頭のBOMがあれば飛ばします(2026-09-19確認)。
対象がShift_JISだったテストでは、次のエラーで止まりました。
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8f in position 0: invalid start byte
終了コード1で停止し、ファイルは変わりませんでした。0x8fはファイルの中身によって変わります。エラーが出た場合は上書きを続けず、後半の判定付き結合を使ってください。
Pythonが無いときはPowerShellで付ける
先に元のファイルをコピーしてください。そのうえで、CSVのあるフォルダでPowerShell 5.1の次の1行を実行します。
$t = Get-Content -Path .\sales.csv -Raw -Encoding UTF8; Set-Content -Path .\sales.csv -Value $t -Encoding UTF8 -NoNewline
BOMなしUTF-8の134バイトのファイルは137バイトになり、先頭はEF BB BFでした。2回実行してもBOMは重ならず、中身と改行(LF)は変わりませんでした。
ただし、Shift_JISのファイルに使うと、エラーが出ないまま日本語が置換文字(�)40個に置き換わりました。PowerShellの1行は、UTF-8かどうかの確認には使えません。Shift_JISかもしれないファイルは、[データ]タブから取り込んでください。PowerShellの1行を実行した後に日本語が�になっていたら、コピーしておいた元のファイルに戻して、[データ]タブから取り込みます。
ファイルを書き換えたくない場合も、Microsoftの案内にある[データ]タブからの取り込み(日本語版の表記は[テキスト/CSV からデータを取得])を使えます(Microsoftサポート、2026-09-19確認)。
AIには「Excelで開く」と伝える
次からCSVを作らせるときは、用途までプロンプトに含めます。今回使った文は次の2つです。

「売上の日本語CSVを3行作って sales.csv に保存して」
「売上の日本語CSVを3行作って sales.csv に保存して。Excelで開くので文字化けしないように」
ZEN AI LABは2026-09-19に、Windows 11 ProのPCでCodex CLIとClaude Code CLIを動かしました。空のフォルダを作業場所にし、標準の設定で3回ずつ実行しました。ユーザー設定を読まない条件でも1回ずつ試し、合わせて16回実行しました。Codexをcodex execで動かす方法は別の記事にまとめています。
| ツール | プロンプト | BOM あり | BOM なし |
|---|---|---|---|
| Codex | Excel と言わない | 2 | 1 |
| Codex | Excelで開くので文字化けしないように | 3 | 0 |
| Claude Code | Excel と言わない | 2 | 2 |
| Claude Code | Excelで開くので文字化けしないように | 4 | 0 |
Codexは標準条件の3回です。Claude Codeは標準条件3回と、ユーザー設定を読まない条件1回です。Codexのユーザー設定を読まない条件の2回は保存できなかったため、表に含めていません。
Excelと言わない文で作られた7ファイルは、BOMありが4つ、BOMなしが3つでした。標準条件ではCodexもClaude Codeも3回中2回がBOMあり、1回がBOMなしでした。Claude Codeのユーザー設定を読まない条件の1回もBOMなしでした。
「Excelで開くので文字化けしないように」と伝えた7ファイルは、すべて先頭3バイトがEF BB BFでした。内訳はCodexが3つ、Claude Codeが4つです。回数が少ないため、別の実行でも同じ結果になるとは限りません。
このテストでは、Claude Codeにファイルの書き込みだけを許可していました。BOMなしの2回は、BOMが無いことと、BOMを付けるコマンドには許可が必要だったことを返答で伝えました。結果には、許可の条件も関係しています。
ほかの依頼文はプロンプト集で確認できます。
AIの「BOM付きです」は先頭を見て確かめる
AIの返答に文字コードの説明があっても、ファイルの実体は先頭3バイトで確かめます。確認には、前に示したPythonコマンドを使います。
AIの最後の返答は、14ファイル中13で文字コードとBOMの有無に触れ、実際のバイトと一致していました。残る1回は、CodexがBOMなしのファイルを作り、文字コードに触れず「保存しました」と返しています。
Claude Codeが「先頭3バイトがBOMであることを確認済み」という趣旨を返した回もありました。そのファイルは実際にBOMありでしたが、どう調べたかは記録に残っていません。
BOM付きのCSV同士はそのまま連結しない
BOMはファイルの先頭に置く目印です。BOM付きのCSVをコピー機能で単純につなぐと、後ろのファイルのBOMが途中に残ります。
ZEN AI LABでは、BOMありのCSVを2つ、copy /b a.csv+b.csv merged.csvで連結しました。BOMは0バイト目と137バイト目の2か所に残りました。utf-8-sigで読んでも、2つ目の見出し行の先頭には見えない文字(U+FEFF)が残りました。
BOM付きのCSVをPythonのcsv.DictReaderでencoding='utf-8'として読むと、row['商品名']がKeyError: '商品名'になりました。列名は'\ufeff商品名'で、先頭に見えない1文字が付いていました。encoding='utf-8-sig'にすると読めました。
複数のCSVはバイトのまま連結せず、ファイルごとに読み込んで見出しとデータを分けます。
Shift_JISが混ざるときはファイルごとに判定する
ZEN AI LABは2026-09-15に、Windows 11 Pro(10.0.26200)とPython 3.13.1で再現テストをしました。同じ3行のデータを、UTF-8(BOMあり)・UTF-8(BOMなし)・Shift_JIS(cp932)の3ファイルに保存しました。
データには①・㈱・髙・~・〜・𠮷を入れました。読み方や書き方を変え、5つの壊れ方を再現しました。
| 症状 | 何が起きたか | 見分け方 |
|---|---|---|
| 読めない文字になる | UTF-8をShift_JISとして読むと、取引先,金額,備考が蜿門シ募..,驥鷹。.,蛯呵.のようになった。BOMありでは先頭にᄏソも付いた | エラーが出ず処理が終わるため、見出しや本文を見る |
| 読み込みが止まる | Shift_JISをUTF-8として読むとUnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 0: invalid start byteで止まった | UnicodeDecodeErrorと指定した文字コードを見る |
| 一部の文字を書けない | 𠮷をcp932で書こうとするとUnicodeEncodeErrorになった。errors='replace'では185バイトから129バイトに減り、その文字が消えた | 書き出し時のエラーと変換前後の内容を見る |
| 見出しが一致しない | BOMを考えずに読むと見出しが['\ufeff取引先', '金額', '備考']となり、h[0] == '取引先'はFalseだった | 先頭3バイトと見出しの実体を見る |
| コンソールで止まる | Windowsのcp932のコンソールへUTF-8の文字をprintするとUnicodeEncodeErrorで止まった | PYTHONIOENCODING=utf-8を付けると再現時は出なくなった |
結合は次の順番で進めます。
- 結合するCSVを
inフォルダに集めます。 - 次のコードを
merge_csv.pyとして、inフォルダがある場所に保存します。 - その場所で
python merge_csv.pyを実行します。
import csv, glob, io
def read_rows(path):
raw = open(path, "rb").read()
for enc in ("utf-8-sig", "cp932"): # utf-8-sig は BOM があってもなくても読める
try:
text = raw.decode(enc)
return enc, list(csv.reader(io.StringIO(text, newline="")))
except UnicodeDecodeError:
continue
raise ValueError(f"文字コードを判定できない: {path}")
header, out_rows = None, []
for path in sorted(glob.glob("in/*.csv")):
enc, rows = read_rows(path)
print(path, enc, rows[0])
if header is None:
header = rows[0]
elif rows[0] != header:
print(" 見出しが違うので結合しない:", path)
continue
out_rows += rows[1:]
with open("merged.csv", "w", encoding="utf-8-sig", newline="") as f:
w = csv.writer(f, lineterminator="\r\n")
w.writerow(header)
w.writerows(out_rows)
print("merged.csv:", len(out_rows), "行")
- 出力された
merged.csvに先頭3バイトを見るコマンドを実行し、EF BB BFを確かめます。
コードは各ファイルをutf-8-sig、cp932の順で読みます。最初のファイルの見出しを基準にし、見出しが違うファイルは結合せずに知らせます。最後にBOM付きのUTF-8でmerged.csvを書き出します。
2026-09-19のテストでは、AIが作った3ファイルを使いました。同じ内容をShift_JISにした1ファイルと、見出しが違う1ファイルも加え、計5ファイルで動かしました。
5ファイルとも文字コードを判定できました。Shift_JISの1つはcp932、残りはutf-8-sigでした。見出しが違う1ファイルは結合せず、残る4ファイルのデータを12行に結合しました。書き出したmerged.csvは先頭にBOMが1つあり、改行はCRLFでした。
2026-09-15の再現では、先頭3バイトがEF BB BFならutf-8-sigと判定しました。違う場合はUTF-8、cp932の順に試しました。3ファイルの文字コードをすべて正しく判定し、9行に結合できました。出力したファイルの先頭3バイトはEF BB BFでした。
このコードが試す文字コードはutf-8-sigとcp932だけです。UTF-16などは判定できず、空のファイルも想定していません。見出しの並びが1文字でも違うファイルは結合しません。
この記事で確かめていないこと
Microsoftの案内には、BOMなしのUTF-8をダブルクリックした場合の読み方や表示の記載がありません。ZEN AI LABの作業用PCにはExcelが入っていないため、実際の画面表示も調べていません。記事内の文字化け例はPythonによるシミュレーションです。
MicrosoftはPower Queryとテキストのインポート機能を案内しています。日本語版には[テキスト/CSV からデータを取得]という表記もありますが、実際のメニュー表示は見ていません。Excelの版によって名前が異なる可能性があります。
ChatGPTのWeb画面でCSVを作成して取得する操作は対象外です。そこで得たCSVにも、先頭3バイトを調べ、UTF-8ならBOMを付ける手順は使えます。
「UTF-8のBOM付きで保存して」という別の文言はテストしていません。Excelで保存形式を選んだ後の文字コードや、LFのCSVを開いた際の表示も調べていません。
今回の結果は2026-09-19時点のCodex CLIとClaude Code CLIによるものです。Codexの標準条件はgpt-5.6-sol、reasoning lowでした。モデル、設定、実行日が変われば結果も変わる可能性があります。
月ごとに分かれたCSVを1つにまとめる作業を毎月くり返すなら、ZEN AI LABが作ったWindows用のツールCSVMergeFlow(noteで販売・自社商品)も使えます。
価格・動作環境・無料版の有無は、CSVMergeFlow の商品ページにまとめています。
まとめ
- 文字化けしたCSVは、先頭3バイトが
EF BB BFかを最初に調べます。 - BOMなしのUTF-8なら、元のファイルをコピーしてからBOMを付けます。
- 複数のCSVは単純に連結せず、ファイルごとに文字コードと見出しを調べます。
- 今日、元のファイルをコピーしてから、先頭3バイトを見るコマンドを実行します。
EF BB BFが無く、UTF-8として読める場合はBOMを付けます。- 次にAIへ頼むときは「Excelで開くので文字化けしないように」と用途まで伝え、受け取ったファイルも調べます。
業務で使う手順を続けて探す場合は、業務の自動化の記事一覧をご覧ください。

