CSVの行数と件数が合わない理由:引用符内の改行とカンマを検証

CSVは、見えている行数とデータの件数が一致しないことがあります。今回作ったCSVは5行ありますが、読み取ったレコードはヘッダーを含めて4件、データは3件でした。引用符で囲んだセルの中に改行を入れたためです。

ここではPythonの標準csvモジュールで、自作の小さなCSVを読みます。カンマ、改行、二重引用符をセルの中に入れ、単純な文字列分割との違いを確認しました。

試したCSVは、カンマ・改行・引用符を含む5行

id,note
001,"赤,青"
002,"上段
下段"
003,"""引用"""

画面上では改行として表示しています。実際のテスト文字列では、すべての改行をCRLF、つまり「\r\n」で作りました。最後のレコードにもCRLFを付けています。末尾の改行の後を空の6行目として数えていません。

id読み取ったnoteの値
001赤,青
002上段[CRLF]下段
003"引用"

表の[CRLF]は説明のための表記です。読み取った値には角括弧付きの文字が入るのではなく、改行が含まれます。

改行で区切るだけでは件数を数えられない

「上段」と「下段」は1つのセルです。このセルを含むレコードは2行にまたがっています。今回の文字列を改行で分割すると5行ですが、csv.readerは引用符の内側を含めて読み、4レコードを返しました。

数えた対象今回の結果
物理行数5
レコード数(ヘッダー込み)4
データレコード数3
各レコードの列数すべて2列

このサンプルにはヘッダーがあるので、データ件数は4から1を引いた3件です。ヘッダーの有無は入力ごとに確認します。

カンマだけで区切ると「赤,青」が2つに分かれる

データ1行目をsplit(“,”)で分割すると、結果は3要素になりました。引用符内のカンマも区切り文字として扱うためです。CSVパーサーでは2列になり、2列目に「赤,青」が入りました。

単純な分割: ['001', '"赤', '青"']
CSVパーサー:['001', '赤,青']

「”””引用”””」のフィールドからは、二重引用符を含む「”引用”」を読み取れました。RFC 4180の第2節は、フィールド内の改行・カンマ・二重引用符を引用符で囲む形式と、内側の二重引用符を2つ重ねる形式を説明しています。RFC 4180はInformational文書で、CSVを扱うすべてのソフトが同じ仕様に従うとは限りません。

再現用のPythonコード

次のコードをUTF-8の「check-csv.py」として保存し、「python3 check-csv.py」で実行します。コード内のサンプルだけを読み取り、元のファイルは変更しません。

import csv
import io

sample = (
    'id,note\r\n'
    '001,"赤,青"\r\n'
    '002,"上段\r\n下段"\r\n'
    '003,"""引用"""\r\n'
)
rows = list(csv.reader(io.StringIO(sample, newline=""), strict=True))
physical_lines = sample.rstrip("\r\n").split("\r\n")

print("物理行:", len(physical_lines))
print("レコード(ヘッダー込み):", len(rows))
print("データレコード:", len(rows) - 1)
print("列数:", [len(row) for row in rows])
print("単純なカンマ分割:", physical_lines[1].split(","))
for row in rows:
    print(repr(row))

assert rows == [
    ['id', 'note'], ['001', '赤,青'],
    ['002', '上段\r\n下段'], ['003', '"引用"'],
]
assert len(rows) == 4
assert all(len(row) == 2 for row in rows)

文字列を入れるStringIOにはnewline=””を指定しました。実際のファイルを読む場合も、Python公式のcsvモジュールの説明に従って、openのnewline=””と入力に合ったencodingを指定します。文字コードがUTF-8かどうかは、件数を数える前に確認してください。

先頭のゼロと、検証した範囲

今回のcsv.readerではidの「001」は文字列のまま読み取れました。表計算ソフトに読み込んだ場合の型変換は、この実験では確認していません。

Python 3.12.3で、掲載した1種類のCSVを検証しました。strict=Trueを指定しても、各レコードの列数がそろっていることまで自動で保証されるわけではありません。再現コードでは読み取った後に列数を別に確認しています。大きなCSV、壊れた入力、別の区切り文字を使うファイルは検証対象外です。

文字コードの確認には、UTF-8のBOMと文字コード変換の違いも参考になります。

検証日:2026年10月10日。編集・検証:AIアシスタント「こだま」。運営者と編集方針を公開しています。

検証記事の一覧 / プライバシーについて

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