csv

Python標準csvで改行ありエスケープありCSVを読み込む


すごく些細なことなのにつまづいてしまったのでメモ。誰かの役に立てば良いです。

入力フォーマット

CSVには改行を含めることができます。改行がある場合は要素をダブルクオート(“)で囲むのが普通です。

また、要素内にダブルクオートがある場合、ダブルクオートを2つ続けるか、バックスラッシュ(\)でエスケープするのが普通です。

入力

このようなCSVファイルを扱いたいけど、上手く行きませんでした。

name,message
Tom,"Hello, my name is \"Tom\""
Yamamoto,"こんにちは
私の名前は\"山本\"
です。"

読み込めはするけど、3行ではなく4行のデータとして扱われました。つまり改行の部分が正しく認識されません。

結論

readerの引数を正しく設定しよう(escapechar)

https://docs.python.org/ja/3/library/csv.html
のあたりの特にDialectが重要です。
https://docs.python.org/ja/3/library/csv.html#csv-fmt-params

ここも分かりやすいかも。
http://ja.pymotw.com/2/csv/#id5

doublequoteがデフォルトTrueなので、つまりエスケープは\“ではなくて""という形式を想定していることになります・・・これにひっかかった。

escapechar=’\\‘を設定することで、エスケープが正しく扱われて、上手く行きました。

例

import csv

print('ng_reader')
with open('data.csv', 'r') as f:
    ng_reader = csv.DictReader(f)
    for row in ng_reader:
        print(row)

print('ok_reader')
with open('data.csv', 'r') as f:
    ok_reader = csv.DictReader(f, escapechar='\\')
    for row in ok_reader:
        print(row)
実行結果

$ python main.py
 ng_reader
 OrderedDict([('name', 'Tom'), ('message', 'Hello, my name is \Tom\""')])
 OrderedDict([('name', 'Yamamoto'), ('message', 'こんにちは\n私の名前は\山本\"')])
 OrderedDict([('name', 'です。"'), ('message', None)])
 ok_reader
 OrderedDict([('name', 'Tom'), ('message', 'Hello, my name is "Tom"')])
 OrderedDict([('name', 'Yamamoto'), ('message', 'こんにちは\n私の名前は"山本"\nです。')]

ng_readerは改行が正しく扱われていないのでdictが壊れてますね。。
ok_readerの方は大丈夫です。

以上です。