CSVを読み込んだ後に、列数・列名・IDの条件を別々に検査します。パーサーがエラーを出さないことだけでは、期待した表であるとは判断できません。
この記事の内容
対象・検証範囲:CPython 3.12.14 / Linux。掲載サンプルと期待する出力を照合。標準ライブラリのみ。
読み込み成功と正常なデータは別
ヘッダーが3列なのに、あるレコードだけ2列しかないCSVでも、readerは行を返すことがあります。後から値を対応付けると、欠けた値を見逃す原因になります。
ここでは「ヘッダーが1行」「列名は空ではなく一意」「各レコードの列数が同じ」「id列は空ではなく一意」という条件を検査します。IDの重複が正当なデータには、そのまま適用しないでください。
不備をまとめて返すコード
空行は無視します。表示する番号は、ヘッダーを先頭とした読み取りレコードの番号であり、セル内改行がある場合の物理行番号ではありません。
import csv
import io
def validate_csv(text):
errors, seen = [], set()
reader = csv.reader(io.StringIO(text, newline=""), strict=True)
try:
header = next(reader, None)
if not header or any(not name.strip() for name in header):
return ["ヘッダーが空、または空の列名があります"]
if len(set(header)) != len(header):
return ["列名が重複しています"]
if "id" not in header:
return ["id列がありません"]
key_index = header.index("id")
for number, row in enumerate(reader, start=2):
if not row:
continue
if len(row) != len(header):
errors.append(f"レコード{number}: 列数が一致しません")
continue
key = row[key_index]
if not key.strip():
errors.append(f"レコード{number}: idが空です")
elif key in seen:
errors.append(f"レコード{number}: idが重複しています")
else:
seen.add(key)
except csv.Error:
errors.append("CSVの引用符などの構文を確認してください")
return errors
bad = "id,name\n001,ノート\n002\n001,ペン\n,ファイル\n"
print("\n".join(validate_csv(bad)))
assert validate_csv("id,name\n001,ノート\n") == []
assert validate_csv("id,id\n001,002\n") == ["列名が重複しています"]
assert validate_csv('id,name\n001,"未終了')
期待する結果
レコード3: 列数が一致しません
レコード4: idが重複しています
レコード5: idが空です
問題がなければ空のリストを返します。変換の前にerrors = validate_csv(text)として実行し、エラーが1件でもあれば出力を作らず止める形に組み込めます。
実ファイルでは文字コードを明示して読み込んでください。文字コードのエラーはCSVの構造検査より先に起こるので、読み込み段階で別に処理します。BOM付きUTF-8にはutf-8-sigの例を使えます。
この検査に含まれないこと
「正常」と判定できるのは、ここで決めた条件を満たすことだけです。日付の実在、金額の範囲、参照先の存在、商品名の正しさなどは検査していません。strict=Trueも、あらゆるCSV仕様や業務ルールを網羅するバリデーターではありません。
このコードはidとIDを区別し、001と 001も別のキーにします。空白だけのキーは拒否しますが、値を勝手に整形しません。表記を揃えるなら元の値を保管し、検査条件と変換条件を分けてください。
自動処理へ入れるとき
検査で見つかった不備をerrors="ignore"などで無視して進める設計にはしません。元ファイルを残し、不備の種類と対象レコードを記録して、出力元の設定を見直します。
まず小さな正常データと壊したデータの両方で試します。その後、結合やJSON変換の前段に検査を置くと、無言でデータを壊す経路を減らせます。
参考にした公式資料
- Python公式: csv — CSVファイルの読み書き確認日:2026.09.20
- RFC 4180: CSVの共通形式確認日:2026.09.20
掲載サンプルは記載のPython環境で実行確認しています。すべてのOS・入力データを保証するものではありません。 編集・検証方針