CHAPTER 5 ・ ファイルとテキストの実践 / Lesson 19
CSV と JSON を実務の形で扱う
文字コード・BOM・区切り文字の違いを乗り越える。読み込みから書き出しまで、壊れにくい書き方です。
このレッスンが終わったら
「CSVは文字コードと区切りを確認して読む。JSONは ensure_ascii=False と indent を付けて書くと、人が読める」と言える。
こんな場面、ありませんか?
銀行のシステムや、古い販売管理ソフトから出力したCSVを、基礎編の書き方で読んだら、いきなりエラーで止まった。そんな経験は、実務でよくあります。原因は、ファイルの中身(文字)の書き方の約束が、思っていたものと違うことです。
この講座の画面では、銀行のCSVの代わりに、コードの中で同じ形式のファイルを作ります(encoding="cp932" で書き出します)。それを、基礎編と同じ書き方で読んでみましょう。
▶ 実行を押すと、ここに結果が出ます
UnicodeDecodeError(この文字コードでは読めません)と出ます。ファイルの書き方(文字コード)と、読むときの指定が、食い違っているのです。
文字コードを合わせて読む
日本の実務で出会う文字コードは、おもに次の3つです。
| 指定する名前 | どこで出会うか | 見分けるヒント |
|---|---|---|
utf-8 | 最近のシステム、Web、Python の標準 | 基礎編の書き方で読める |
utf-8-sig | Excel の「CSV UTF-8」で保存したもの | 読むと、1つ目の見出しの前に目に見えない文字が付く |
cp932 | 銀行、古い会計・販売管理ソフト、Windows 版 Excel の「CSV」 | utf-8 で読むと UnicodeDecodeError |
cp932(シフトJISの仲間)のファイルは、encoding="cp932" と指定すれば読めます。
▶ 実行を押すと、ここに結果が出ます
もう1つの落とし穴です。Excel が作る UTF-8 のCSVには、先頭にBOMという目印が付くことがあります。utf-8 のまま読むと、見出しの文字が変わってしまいます。
▶ 実行を押すと、ここに結果が出ます
1つ目の見出しが '\ufeff得意先名' になっています。目に見えない BOM が見出しの一部になり、row["得意先名"] と書くと KeyError になります。utf-8-sig なら、BOM が取り除かれます。
書き出しの仕組みを読む
読むときと同じく、書き出すときも文字コードを指定します。open の部品を分けてみます。
"summary.csv"ファイルの名前"w"書き込みモードencoding="utf-8-sig"文字コード(Excelで開いても化けない)newline=""改行の自動変換を止める(csv モジュールの決まり)そして、辞書のリストをCSVに書き出す csv.DictWriter は、次の3ステップです。
with open(...) as f:書き込み用にファイルを開く w = csv.DictWriter(f, fieldnames=["部署", "売上"])「部署」「売上」の列で書く係を用意する w.writeheader()1行目に、見出しを書く w.writerows(rows)辞書のリスト rows を、1行ずつ書く日本語にすると、「summary.csv を Excel でも化けない文字コードで開き、見出しを書いてから、rows を1行ずつ書く」です。
newline="" は、Windows で行と行のあいだに空行が入るのを防ぐ指定です。意味を覚えなくてよいので、CSVを書くときは必ず付けると決めてしまいましょう。
変えて、試す
① 集計結果をCSVに書き出す。 sales.csv を部署ごとに合計して、summary.csv に書きます。書いたあとで読み直し、中身を確かめます。
この欄では、サンプルファイルが使えます。実行のたびに、ファイルは最初の状態に戻ります。
▶ 実行を押すと、ここに結果が出ます
② 値にカンマやダブルクォートが入るとき。 摘要に「文具, 事務用品」のようにカンマが入ると、そのまま書くと列がずれてしまいます。csv は、そういう値を自動でダブルクォートで囲みます。また、区切りがカンマでなくタブ(\t)のファイルは、delimiter で区切り文字を伝えます。
▶ 実行を押すと、ここに結果が出ます
囲まれた値は、読み込むときに元のカンマ入りの値に戻ります。読む側にも delimiter="\t" を渡している点に注意してください。
③ JSON を、人が読める形で書く。 JSONは、json.dumps で文字にできます。日本語の部分が 会 のような記号になるのを、ensure_ascii=False で防ぎ、indent=2 で字下げして読みやすくします。
▶ 実行を押すと、ここに結果が出ます
1行目の \u4f1a のような書き方はエスケープと呼ばれ、コンピュータには正しく伝わりますが、人には読めません。日付(date)をそのまま入れると、JSON にできずエラーになります。
▶ 実行を押すと、ここに結果が出ます
TypeError(日付は JSON にできません)と出ます。default=str を付けると、JSON にできない値を、文字にして書きます("2025-09-30" になります)。
④ 設定ファイルとして使う。 税率やフォルダ名のように、変わりやすい値をコードの外に出すときも JSON が便利です。書いて、読み直します。
▶ 実行を押すと、ここに結果が出ます
dumps / loads は「文字との変換」、dump / load は「ファイルとの読み書き」です(s は string の s)。
自分で書く
お題① 部署ごとの合計 totals を summary.csv に書き出し(Excel で開いても化けない文字コードで)、書いたファイルを読み直して表示してください。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
rows = [{"部署": k, "売上": v} for k, v in totals.items()] で作ります。書くときは encoding="utf-8-sig", newline=""。読み直すときも encoding="utf-8-sig" にしないと、先頭に BOM が付いて見えます。
答えの例を見る
import csv
totals = {"営業": 1110000, "企画": 540000}
rows = [{"部署": k, "売上": v} for k, v in totals.items()]
with open("summary.csv", "w", encoding="utf-8-sig", newline="") as f:
w = csv.DictWriter(f, fieldnames=["部署", "売上"])
w.writeheader()
w.writerows(rows)
print(open("summary.csv", encoding="utf-8-sig").read())お題② 辞書 data を、日本語がそのまま読める形で、字下げ2つで表示してください。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
json.dumps(data, ensure_ascii=False, indent=2) を print します。
答えの例を見る
import json
data = {"会社": "サクラ商事", "部署": ["営業", "企画"]}
print(json.dumps(data, ensure_ascii=False, indent=2))お題③ cp932 で作られた bank.csv を読み、入金額の合計を表示してください。ファイルを作る部分は、最初から書いてあります。
▶ 実行を押すと、ここに結果が出ます
ヒントを見る
open("bank.csv", encoding="cp932") で開き、csv.DictReader で読みます。入金額は文字なので int() に直してから足します。
答えの例を見る
import csv
with open("bank.csv", "w", encoding="cp932", newline="") as f:
f.write("得意先名,入金額\nアオイ電機,1320000\nミドリ商事,484000\nサクラ印刷,792000\n")
with open("bank.csv", encoding="cp932") as f:
total = sum(int(row["入金額"]) for row in csv.DictReader(f))
print(total)仕事ならどう使う?
理解チェック集計結果を CSV に書いて、Excel でそのまま開いても文字化けしないようにしたい。open の encoding は、どれがよいでしょう?
理解チェックjson.dumps で書いた結果の日本語が、\u4f1a のような記号になってしまいました。直すには?