CSVは4行なのにデータが2件?Pythonのcsv.readerで「物理行」と「レコード」を数え分ける

プログラミング・Web開発カテゴリを表すパンダのイラスト プログラミング・Web開発

この記事について
この記事は、生成AIを活用した自動生成フローで作成しています。Pythonの公式CSV仕様と既存Daily Codeサンプルの検証記録を基に、架空のCSVで物理行数とレコード数の違いを解説します。P1〜P5の5視点による自己審査であり、独立AI審査ではありません。

検証ステータス:🧪 既存サンプルのLinux/Python 3.13.5テスト記録は12件PASS。記事公開環境・Windows/macOSは未検証

CSVは4行なのにデータが2件?Pythonのcsv.readerで「物理行」と「レコード」を数え分ける

CSVファイルを開くと4行あるのに、取り込んだデータは2件しかない。これは必ずしも欠落や読み取り失敗ではありません。引用符で囲まれたセルの中に改行が入っていると、ファイル上の複数行がCSV上の1レコードになるためです。Python標準の csv.reader を使うと、改行を含むセルを壊さず、データ件数を数えられます。

どんなときに困るのか

問い合わせ一覧やアンケート結果をCSVに出すと、「備考」「自由記述」「作業メモ」などに改行が入ることがあります。監視担当がテキストエディタの行番号や wc -l の値だけを見て「取込件数が足りない」と判断すると、実際には正常なCSVを障害と誤認してしまいます。反対に、引用符が壊れたCSVを正常として扱うのも危険です。

この違いを理解するため、次の3つを区別します。

数える対象今回の意味注意点
物理行ファイル内の改行で区切られる表示上の行引用符の内側にある改行も含む
CSVレコードCSVパーサーが1件として返す行データ複数の物理行にまたがることがある
データ件数CSVレコードからヘッダー1件を除いた数ヘッダーの有無は業務ごとに確認する

今回の教材は「ヘッダーが必ず1件あるUTF-8 CSV」を前提にしています。すべてのCSVにヘッダーがあるわけではないため、一般的なCSVの総レコード数と、ここで出す CSV_RECORDS は同じ意味ではありません。

まずは架空のCSVを見てみる

サンプルの demo.csv は、次の内容です。Aのメモ欄だけが2行になっています。

id,note
A,"line1
line2"
B,done

テキスト上では4行ですが、CSVの解釈ではヘッダー、A、Bの3レコードです。データだけならAとBの2件です。Aの note セルには line1 と line2 の間の改行が含まれています。引用符は、カンマや改行を含む値を一つのフィールドとして表すために使われます。

単純に1行ずつ文字列を分割すると、Aのメモの後半を新しいレコードと誤認する恐れがあります。CSVはただの「カンマで区切った行」の集合ではなく、引用符を解釈する必要がある形式です。自前の split(',') で取り込まない理由はここにあります。

準備と実行手順

追加パッケージは不要です。Python 3.9以降を想定しています。今回の実測はPython 3.13.5で行いました。コード、テスト、架空CSV、READMEは記事末尾のGitHubサンプルにまとめています。

  1. サンプルフォルダを取得し、audit_csv.py、demo.csv、test_audit_csv.py を同じフォルダに置きます。

  2. ターミナルを開き、そのフォルダへ移動します。

  3. 次のコマンドを一つずつ実行します。

python3 --version
python3 audit_csv.py demo.csv
python3 -m unittest discover -p 'test_*.py' -v

Windowsで python3 が認識されない場合は、Pythonのインストール状態を確認し、py -3 で試してください。Windows上で同じコマンドを実行した実測はまだありません。PowerShellとBashでコマンドを混同せず、まずバージョン表示を確認します。

今回のLinux/Python 3.13.5で実測したCLI出力は次のとおりです。

STATUS=OK
PHYSICAL_LINES=4
CSV_RECORDS=2
HEADER_COLUMNS=2
MULTILINE_RECORDS=1

PHYSICAL_LINES=4 は表示上の4行、CSV_RECORDS=2 はヘッダーを除いた2件を意味します。MULTILINE_RECORDS=1 は、複数の物理行にまたがったデータレコードが1件あるという意味です。数値が違っても、ただちに異常ではありません。

Pythonはどうやって区別しているのか

教材の中心は、Python標準ライブラリの csv.reader です。重要な部分だけを抜き出すと次のようになります。

import csv

with open('demo.csv', encoding='utf-8-sig', newline='') as file:
    reader = csv.reader(file, strict=True)
    header = next(reader)
    records = sum(1 for row in reader)
    print('データ件数:', records)

newline='' は、改行の扱いをCSVパーサーに任せるための指定です。Python公式ドキュメントもCSVファイルを開くときに指定するよう説明しています。utf-8-sig はUTF-8のBOMが付いたファイルも読めるようにするための指定です。文字コードを自動判定しているわけではなく、Shift_JIS等のファイルを読み取れる保証はありません。

next(reader) は最初のCSVレコードをヘッダーとして取り出します。その後の繰り返しで数えているのは、テキストの改行数ではなく、パーサーが返すデータレコードの数です。strict=True は不正なCSV形式に対してエラーを出しやすくする設定ですが、業務項目の値が正しいかまでは検査しません。

公式仕様には reader.line_num という属性もあります。名前だけ見ると「何件目のデータか」と思いがちですが、これは元の入力から読んだ物理行の位置です。引用符の中に改行があれば、レコード数と一致しません。教材の完全版では、直前の line_num と比較して、複数行にまたがるデータレコードを数えています。

1条件だけ変えると結果はどうなるか

Aのメモを1行に直した別名のCSVを作り、元の demo.csv はそのまま残します。

id,note
A,line1
B,done

この場合の期待値(この変更後ファイル自体は今回未実行)は PHYSICAL_LINES=3、CSV_RECORDS=2、MULTILINE_RECORDS=0 です。データ件数は変わらず、物理行数だけが1減ります。この比較から、物理行数の増減だけでデータ増減を判断できないことが分かります。

なお、Windowsで多いCRLF改行でも、教材は \r\n を一つの物理改行として数えます。CRLFのケースは単体テストで実行済みです。ただし、文字コードや区切り文字が異なるすべてのCSVを自動判別するプログラムではありません。

失敗時は終了コードと理由を確認する

完全版は、CSVの中身や実ファイルパスを標準出力に表示せず、数値とエラー種別だけを出すようにしています。架空ファイルで試した場合の結果は次のとおりです。

状況出力の例終了コード確認すること
正常なCSVSTATUS=OK0ヘッダーの有無と期待件数
列数が合わないISSUE=FIELD_COUNT_MISMATCH2カンマ、引用符、元データの形式
引用符が閉じていない・不正UTF-8ISSUE=PARSE_OR_ENCODING_ERROR2ファイル形式と文字コード
ファイルがない・読めないISSUE=READ_ERROR3指定パス、権限、ファイル存在
ファイルが1MiBを超えるISSUE=TOO_LARGE3教材のサイズ制限

今回のテストでは、正常・CRLF・BOM・末尾改行なし・空ファイル・列数不一致・引用符の閉じ忘れ・不正UTF-8・ファイル不存在・サイズ超過など12件すべて成功しました。python3 -m py_compile も成功しています。実行したのは隔離Linuxコンテナであり、Ubuntu本番やWordPressを操作した結果ではありません。

ファイルがないときは STATUS=READ_ERROR ISSUE=READ_ERROR を出して終了コード3となることをCLIで確認しました。自動処理へ組み込む場合は、出力に STATUS=OK があるかだけでなく、終了コードが0かどうかを判定してください。失敗しても後続工程を続けると、件数を確認できなかったこと自体が見落とされます。

実務へ持ち込む前に知っておくこと

今回の教材は1MiB以下のUTF-8 CSVをメモリへ読み込む、読み取り専用の検査です。巨大なファイルを扱う用途では、ストリーミング読み込みや別のサイズ制御が必要です。また、列数が一致しても「注文番号が重複していない」「日付が正しい」「金額が妥当」といった業務上の品質は証明できません。ヘッダー名の重複や型検査も別の課題です。

物理行数の比較は「取込件数がおかしい」と相談されたときの最初の切り分けに向いています。まず入力CSVの形式、ヘッダー、引用符内改行、文字コードを確かめ、次に実際のCSVレコード数を数えます。その後に、取り込み先での除外条件、重複除去、エラー行の扱いを確認するのが自然な順序です。

実顧客のCSVをそのままAIや外部サービスへ送信する必要はありません。今回のような架空の2件で原因を再現できれば、機密情報を使わずに仕組みを理解できます。ファイル内容をログに出さない設計でも、実運用で使う前にはログ保存先や権限を確認してください。

まとめ

CSVの「4行」と「2件」は両立します。引用符で囲まれたセル内の改行を、csv.reader は一つのレコードの一部として解釈するからです。CSVの件数を確認するときは、物理行と論理レコードを区別し、ヘッダーの扱いを明示しましょう。newline=''、文字コード指定、異常系の終了コードまでそろえると、取り込みトラブルの説明が具体的になります。

公式情報・一次情報

GitHubサンプル

文書情報

記事タイトル
CSVは4行なのにデータが2件?Pythonのcsv.readerで「物理行」と「レコード」を数え分ける
作成日
更新日
Source URL
https://papanda925.com/?p=18269

ライセンス: 本記事のうち、当サイトが権利を有する本文・自作図表は、特記なき限り CC BY 4.0 で利用できます。生成AIを活用して作成・編集した内容を含みます。コードについて、別途ライセンス表示またはリンク先GitHubリポジトリのライセンスがある場合は、その条件を優先します。引用・第三者資料・画像・商標等は本ライセンスの対象外です。 利用ポリシー

タイトルとURLをコピーしました