Pythonでのcsvファイルの編集方法をまとめる
目的
最近、Pythonでcsvを編集する機会がありました。そこで、そのときに得た知識をまとめておこうと思います。Pythonでcsvファイルを操作するには、標準ライブラリのcsvモジュールとPandasを使用する方法があるようでしたが、今回は標準ライブラリのcsvモジュールを使用しました。参考にしたのは公式ドキュメントです。
14.1. csv --- CSV ファイルの読み書き — Python 3.5.10 ドキュメント
公式ドキュメントはかなり情報が多いですが、私のような初心者にはわかりにくい表現ばかりだったので、なるべく平易にまとめるように努力しました。
csvモジュールのインポート
まず、csvモジュールをインポートしておきます。
import csv
csvファイルの読み込み方
ヘッダーの無い場合
まずは、ヘッダーなどはなく、ただデータが並べられているcsvファイルをオープンする方法を紹介します。
# example.csv 佐藤,一郎,20 高橋,二郎,21
まず、csvファイルの最もシンプルな開き方は次のようにすることができます。
with open('example.csv', 'rt', newline='') as csvfile: # まず、ファイルをオープンする reader = csv.reader(csvfile) # csvモジュールのreader関数でreaderという変数名のreaderオブジェクトを作成する profile = [row for row in reader] # リスト内包表記によりreaderの中身をリストに追加していく。for文でも可
上のコードを実行すると、profileという変数名のリストが作られます。
profile
Output:
[['佐藤', '一郎', '20'], ['高橋', '二郎', '21']]
上記の説明をします。まず、一行目については、ファイルのオープンとクローズを自動的に行ってくれる構文と思ってください。open
で'example.csv'という名前のファイルを開きます。'rt'
は読み込み(read)かつテキストモード(text)で開くことを指定しています。newline=''
を指定しておくことはおまじないとして公式ドキュメントで推奨されています。
newline='' が指定されない場合、クォートされたフィールド内の改行は適切に解釈されず、書き込み時に \r\n を行末に用いる処理系では余分な \r が追加されてしまいます。csv モジュールは独自 (universal newlines) の改行処理を行うため、newline='' を指定することは常に安全なはずです。
(なるほどわからん)
as
の後ろで指定する変数名はオープンしたファイル(Pythonではファイルオブジェクトというオブジェクトだそう)を参照するのに使われます。
次の行では、csvモジュールのreader関数を用いてcsvfileという変数名のオブジェクトからreaderという変数名のオブジェクト(readerオブジェクトというそう)を作成します。readerオブジェクトはイテレータとして使用することができ、つまりfor文によりループをすることができます。このとき1ループで扱われるオブジェクトは、csvファイル内の各行がカンマごとに文字列として分割されたリストになります。for文で実際に確認すると以下のようになります。
with open('example.csv', 'rt', newline='') as csvfile: reader = csv.reader(csvfile) for row in reader: print(row)
Output:
['佐藤', '一郎', '20'] ['高橋', '二郎', '21']
が1ループで扱われます。
最後の
profile = [row for row in reader]
によりreaderオブジェクトからリストを取り出し、example.csvというファイル内のデータが文字列のリストのリストとしてPythonで扱うことができる形になりました。
ヘッダーを指定して、辞書として読み込む場合
次に、各列にヘッダーを指定して、Pythonの辞書としてデータを読み込む方法を説明します。それには、以下のようにします。
with open('example.csv', 'rt', newline='') as csvfile: reader = csv.DictReader(csvfile, fieldnames=['姓', '名', '年齢']) profile = [row for row in reader]
上記のコードを実行すると以下のような、OrderedDictを要素としたリストが得られます。
profile
Output:
[OrderedDict([('姓', '佐藤'), ('名', '一郎'), ('年齢', '20')]), OrderedDict([('姓', '高橋'), ('名', '二郎'), ('年齢', '21')])]
csvモジュールのDictReader
はfieldnames
に渡されたリストに指定されたヘッダーをキーとした辞書を返すイテレータを作成します。各キーのバリューにはexample.csvの各行の値が渡されます。
また、以下のようにcsvファイルの一行目にヘッダーが書かれている場合、DictReader
のfieldnames
を省略すると、自動的に一行目の値を辞書のキーとして処理をします。
# example2.csv 姓,名,年齢 佐藤,一郎,20 高橋,二郎,21
with open('example2.csv', 'rt', newline='') as csvfile: reader = csv.DictReader(csvfile) profile = [row for row in reader]
profile
Output:
[OrderedDict([('姓', '佐藤'), ('名', '一郎'), ('年齢', '20')]), OrderedDict([('姓', '高橋'), ('名', '二郎'), ('年齢', '21')])]
csvファイルの書き込み方
次に、csvファイルを作成して書き込む方法を説明します。
一行ずつ書き込む場合
まず、一行ずつ書き込む方法を説明します。一行ずつ書き込むには以下のようにします。
with open('write_example.csv', 'wt', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerow(['佐藤', '一郎', '20']) writer.writerow(['高橋', '二郎', '21']) writer.writerow(('渡辺', '三郎', '21'))
上記のコードを実行すると以下のようなwrite_example.csvファイルが作成されます。
# write_example.csv 佐藤,一郎,20 高橋,二郎,21 渡辺,三郎,21
上記のコードの説明をします。まず、open
の引数で'wt'
を指定し、書き込み(write)かつテキストモードで開きます。
次に、csvモジュールのwriter
関数により、writerという変数名のオブジェクト(writerオブジェクトというそう)を作成します。このwriterオブジェクトはwriterow
というメソッドを備えており、引数としてリスト(やタプル)を渡すと、それらの要素をカンマで区切り、write_example.csvへ書き込みます。
一度に複数行を書き込む場合
以下のようにwriterows
メソッドを使用すると、リスト(やタプル)のリストを一行ずつ書き込むことができます。
profile = [['佐藤', '一郎', '20'], ['高橋', '二郎', '21'], ('渡辺', '三郎', '21')] with open('write_example.csv', 'wt', newline='') as csvfile: writer = csv.writer(csvfile) writer.writerows(profile)
ヘッダーを指定して書き込む場合
ヘッダーを指定して書き込むには以下のようにDictWriter
を使用します。
with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21'})
上記のコードを実行すると以下のwrite_example2.csvが得られます。
# write_example2.csv 姓,名,年齢 佐藤,一郎,20 高橋,二郎,21
上記のコードの説明をします。csvモジュールのDictWriter
にファイルオブジェクトcsvfile
とfieldnames
引数を渡します。fieldnames
にはcsvファイルのヘッダーを指定します。
そして、writerow
メソッドには、fieldnames
で指定したヘッダーをキーとする辞書を渡してwrite_example2.csvファイルへ記入していきます。
ちなみに、writer.writeheader()
はwrite_example2.csvファイルにヘッダーを書き込むコマンドなので、ヘッダーを書き込みたくない場合は省略できます。
ヘッダーを指定して一度に複数書き込む場合
また、以下のようにwriterows
メソッドを使用すると辞書のリストを書き込むことができます。これも上記と同じwrite_example2.csvファイルを作ることができます。
profile = [{'姓': '佐藤', '名': '一郎', '年齢': '20'}, {'姓': '高橋', '名': '二郎', '年齢': '21'}] with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(profile)
ヘッダーに指定したキーを全て持たない辞書を入力する際の処理
デフォルトでの動作
以下のコードのように、fieldnames
で['姓', '名', '年齢', '結婚']
を指定してみます。このとき、{'姓': '佐藤', '名': '一郎', '年齢': '20'}
と{'姓': '高橋', '名': '二郎', '年齢': '21'}
は結婚というキーを持ちません。この場合は、結婚の列にあたる部分は空欄になります。write_example2.csvの佐藤さん、高橋さんの行の右端にコンマのみが記入されているので、空欄が記入されていることがわかります。
profile = [{'姓': '佐藤', '名': '一郎', '年齢': '20'}, {'姓': '高橋', '名': '二郎', '年齢': '21'}] with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(profile) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚'})
# write_example2.csv 姓,名,年齢,結婚 佐藤,一郎,20, 高橋,二郎,21, 渡辺,三郎,24,既婚
restval
による足りないキーの処理
上のコードでは、存在しないキーの箇所には空欄が記入されましたが、DictWriter
のrestval
を指定すると、指定した文字列を補います。以下のコードでは、restval='未記入'
を指定して、結婚というキーを持たない辞書を書き込む際に未記入という文字列を補うようにしてあります。
with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, restval='未記入') writer.writeheader() writer.writerows(profile) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚'})
姓,名,年齢,結婚 佐藤,一郎,20,未記入 高橋,二郎,21,未記入 渡辺,三郎,24,既婚
ヘッダーに指定ていないキーを持つ辞書を入力する際の処理
デフォルトでの動作
以下のコードのように、fieldnames = ['姓', '名', '年齢', '結婚']
のようにヘッダーを指定しているときに、コメントというキーを持つ辞書を書き込むとエラーになります。
profile = [{'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未記入'}, {'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未記入'}] with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames) writer.writeheader() writer.writerows(profile) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'})
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-83-251ee449288c> in <module> 5 writer.writerows(profile) 6 writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚'}) ----> 7 writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'}) ~\Anaconda3\lib\csv.py in writerow(self, rowdict) 153 154 def writerow(self, rowdict): --> 155 return self.writer.writerow(self._dict_to_list(rowdict)) 156 157 def writerows(self, rowdicts): ~\Anaconda3\lib\csv.py in _dict_to_list(self, rowdict) 149 if wrong_fields: 150 raise ValueError("dict contains fields not in fieldnames: " --> 151 + ", ".join([repr(x) for x in wrong_fields])) 152 return (rowdict.get(key, self.restval) for key in self.fieldnames) 153 ValueError: dict contains fields not in fieldnames: 'コメント'
extrasaction
によるヘッダーに存在しないキーの処理
上のコードのように、ヘッダーに指定していないキーを持つ辞書を書き込もうとするとエラーが出ます。しかし、DictWriter
のextrasaction
に'ignore'
を指定すると、エラーを無視してcsvファイルに書き込みを行います。
with open('write_example2.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, extrasaction='ignore') writer.writeheader() writer.writerows(profile) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'})
# write_example2.csv 姓,名,年齢,結婚 佐藤,一郎,20,未記入 高橋,二郎,21,未記入 渡辺,三郎,24,既婚 鈴木,四郎,25,未婚
その他のオプションについて
コンマ以外の区切り文字
writer
関数のdelimiter
をしていすると、区切り文字をコンマから変更することができます。例えば、以下のようにdelimiter=' '
を指定すると、出力されるcsvファイルはスペース区切りになります。
profile = [['佐藤', '一郎', '20'], ['高橋', '二郎', '21'], ('渡辺', '三郎', '21')] with open('write_example3.csv', 'wt', newline='') as csvfile: writer = csv.writer(csvfile, delimiter=' ') writer.writerows(profile)
#write_example3.csv 佐藤 一郎 20 高橋 二郎 21 渡辺 三郎 21
また、読み込む場合でもdelimiter
を指定することができます。以下のように、delimiter
を指定するのとしないのでは、読み込まれるリストの中身が変わってきます。以下は、上で作成したwrite_example3.csvファイルを読み込んだ時の例です。
# delimiter指定なし with open('write_example3.csv', 'rt', newline='') as csvfile: reader = csv.reader(csvfile) for row in reader: print(row)
Output:
# 一行が一つの文字列として読み込まれる ['佐藤 一郎 20'] ['高橋 二郎 21'] ['渡辺 三郎 21']
# delimiter指定あり with open('write_example3.csv', 'rt', newline='') as csvfile: reader = csv.reader(csvfile, delimiter=' ') for row in reader: print(row)
Output:
# スペースごとに区切られた文字列のリストとして読み込まれる。 ['佐藤', '一郎', '20'] ['高橋', '二郎', '21'] ['渡辺', '三郎', '21']
書き込み時のクオーティング
書き込む文字列にコンマ等の文字列が含まれているが、それを一つの要素として扱いたい場合がある。その時はwriter
やDictWriter
のquoting
を指定する。
全部をクオーティングする場合
quoting=csv.QUOTE_ALL
を指定すると、書き込み時にすべての項目をクオーティングする。
with open('write_example4.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_ALL) writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'})
# write_example4 "姓","名","年齢","結婚","コメント" "佐藤","一郎","20","未婚","お金欲しい" "高橋","二郎","21","未婚","時間が,欲しい" "渡辺","三郎","24","既婚","お腹すいた" "鈴木","四郎","25","未婚","彼女ほしい"
また、クオーティングの記号もquotechar
により指定することができます。以下では、quotechar="'"
を指定して、シングルクオートでクオーティングするようにしてあります。
with open('write_example5.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_ALL, quotechar="'") writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'})
'姓','名','年齢','結婚','コメント' '佐藤','一郎','20','未婚','お金欲しい' '高橋','二郎','21','未婚','時間が,欲しい' '渡辺','三郎','24','既婚','お腹すいた' '鈴木','四郎','25','未婚','彼女ほしい'
delimiter
、quotechar
またはlineterminator
を含む文字列のみをクオーティングする場合
区切り文字(delimiter
)、クオート文字(quotechar
)または改行文字(lineterminator
)を含む文字列のみをクオートする場合はquoting=csv.QUOTE_MINIMAL
を指定します。以下の例では、"時間が,欲しい"
という文字列にdelimiter
である","
が含まれているので、write_example6.csvには"時間が,欲しい"というようにクオーティングされた文字列が出力されています。同様に、 '"彼女"ほしい'という文字列にはquotechar
である'"'
が含まれているので、write_example6.csvには"""彼女""ほしい"というようにクオーティングされた文字列が出力されています。ただし、'"彼女"ほしい'のダブルクオートが二つ重ねて出力されるようです。
with open('write_example6.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_MINIMAL) writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '"彼女"ほしい'})
# write_example6.csv 姓,名,年齢,結婚,コメント 佐藤,一郎,20,未婚,お金欲しい 高橋,二郎,21,未婚,"時間が,欲しい" 渡辺,三郎,24,既婚,お腹すいた 鈴木,四郎,25,未婚,"""彼女""ほしい"
非数値のみをクオーティングする場合
以下のように、辞書のバリューに整数と文字列が含まれる場合に、文字列のみをクオーティングするにはquoting=csv.QUOTE_NONNUMERIC
を指定します。
with open('write_example7.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_NONNUMERIC) writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': 20, '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': 21, '結婚': '未婚', 'コメント': '時間が欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': 24, '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': 25, '結婚': '未婚', 'コメント': '彼女ほしい'})
# write_example7.csv "姓","名","年齢","結婚","コメント" "佐藤","一郎",20,"未婚","お金欲しい" "高橋","二郎",21,"未婚","時間が欲しい" "渡辺","三郎",24,"既婚","お腹すいた" "鈴木","四郎",25,"未婚","彼女ほしい"
クオーティングはせず、エスケープ文字により処理する場合
クオーティングではなく、エスケープ文字を指定することによりdelimiter
やquotechar
を処理する場合は以下のようにします。まず、quoting=csv.QUOTE_NONE
を指定します。これは、書き込み時にクオーティングは一切せず、delimiter
やquotechar
が文字列に現れた場合はescapechar
に指定した文字列でエスケープするようなオプションです。(ドキュメントにはdelimiter
のみをエスケープすると書かれていましたが、quotechar
もエスケープするようです。)今回はescapechar='\\'
を指定しました。
with open('write_example8.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_NONE, escapechar='\\') writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '"彼女"ほしい'})
# write_example8.csv 姓,名,年齢,結婚,コメント 佐藤,一郎,20,未婚,お金欲しい 高橋,二郎,21,未婚,時間が\,欲しい 渡辺,三郎,24,既婚,お腹すいた 鈴木,四郎,25,未婚,\"彼女\"ほしい
ちなみに、escapechar
を指定しないとエラーになります。
with open('write_example8.csv', 'wt', newline='') as csvfile: fieldnames = ['姓', '名', '年齢', '結婚', 'コメント'] writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_NONE) writer.writeheader() writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'})
--------------------------------------------------------------------------- Error Traceback (most recent call last) <ipython-input-103-dbe28ebf55ec> in <module> 4 writer.writeheader() 5 writer.writerow({'姓': '佐藤', '名': '一郎', '年齢': '20', '結婚': '未婚', 'コメント': 'お金欲しい'}) ----> 6 writer.writerow({'姓': '高橋', '名': '二郎', '年齢': '21', '結婚': '未婚', 'コメント': '時間が,欲しい'}) 7 writer.writerow({'姓': '渡辺', '名': '三郎', '年齢': '24', '結婚': '既婚', 'コメント': 'お腹すいた'}) 8 writer.writerow({'姓': '鈴木', '名': '四郎', '年齢': '25', '結婚': '未婚', 'コメント': '彼女ほしい'}) ~\Anaconda3\lib\csv.py in writerow(self, rowdict) 153 154 def writerow(self, rowdict): --> 155 return self.writer.writerow(self._dict_to_list(rowdict)) 156 157 def writerows(self, rowdicts): Error: need to escape, but no escapechar set
読み込み時のクオーティングの処理
クオーティングされていないフィールドをフロート型として読み込む
以下のexample3.csvのように、数字以外がクオーティングされているcsvファイルを読み込む際に、数字のフィールドをPythonのフロート型として読み込むことができます。
# example3.csv "姓","名","年齢","結婚","コメント" "佐藤","一郎",20,"未婚","お金欲しい" "高橋","二郎",21,"未婚","時間が欲しい" "渡辺","三郎",24,"既婚","お腹すいた" "鈴木","四郎",25,"未婚","彼女ほしい"
そのためには、quoting=csv.QUOTE_NONNUMERIC
を指定します。
with open('example3.csv', 'rt', newline='') as csvfile: reader = csv.DictReader(csvfile, quoting=csv.QUOTE_NONNUMERIC) profile = [row for row in reader]
profile
Output:
[OrderedDict([('姓', '佐藤'), ('名', '一郎'), ('年齢', 20.0), ('結婚', '未婚'), ('コメント', 'お金欲しい')]), OrderedDict([('姓', '高橋'), ('名', '二郎'), ('年齢', 21.0), ('結婚', '未婚'), ('コメント', '時間が欲しい')]), OrderedDict([('姓', '渡辺'), ('名', '三郎'), ('年齢', 24.0), ('結婚', '既婚'), ('コメント', 'お腹すいた')]), OrderedDict([('姓', '鈴木'), ('名', '四郎'), ('年齢', 25.0), ('結婚', '未婚'), ('コメント', '彼女ほしい')])]
クオート文字をそのまま読み込む場合
example3.csvのように、クオートされているフィールドが含まれるファイルを読み込もうとすると
# example3.csv "姓","名","年齢","結婚","コメント" "佐藤","一郎",20,"未婚","お金欲しい" "高橋","二郎",21,"未婚","時間が欲しい" "渡辺","三郎",24,"既婚","お腹すいた" "鈴木","四郎",25,"未婚","彼女ほしい"
以下のように自動的に変換されて読み込まれます。
with open('example3.csv', 'rt', newline='') as csvfile: reader = csv.DictReader(csvfile) profile = [row for row in reader]
profile
Output:
[OrderedDict([('姓', '佐藤'), ('名', '一郎'), ('年齢', '20'), ('結婚', '未婚'), ('コメント', 'お金欲しい')]), OrderedDict([('姓', '高橋'), ('名', '二郎'), ('年齢', '21'), ('結婚', '未婚'), ('コメント', '時間が欲しい')]), OrderedDict([('姓', '渡辺'), ('名', '三郎'), ('年齢', '24'), ('結婚', '既婚'), ('コメント', 'お腹すいた')]), OrderedDict([('姓', '鈴木'), ('名', '四郎'), ('年齢', '25'), ('結婚', '未婚'), ('コメント', '彼女ほしい')])]
これをクオート文字を含めて読み込みたい場合はquoting=csv.QUOTE_NONE
を指定して読み込みます。
with open('example3.csv', 'rt', newline='') as csvfile: reader = csv.DictReader(csvfile, quoting=csv.QUOTE_NONE) profile = [row for row in reader]
profile
Output:
[OrderedDict([('"姓"', '"佐藤"'), ('"名"', '"一郎"'), ('"年齢"', '20'), ('"結婚"', '"未婚"'), ('"コメント"', '"お金欲しい"')]), OrderedDict([('"姓"', '"高橋"'), ('"名"', '"二郎"'), ('"年齢"', '21'), ('"結婚"', '"未婚"'), ('"コメント"', '"時間が欲しい"')]), OrderedDict([('"姓"', '"渡辺"'), ('"名"', '"三郎"'), ('"年齢"', '24'), ('"結婚"', '"既婚"'), ('"コメント"', '"お腹すいた"')]), OrderedDict([('"姓"', '"鈴木"'), ('"名"', '"四郎"'), ('"年齢"', '25'), ('"結婚"', '"未婚"'), ('"コメント"', '"彼女ほしい"')])]
Dialectについて
ダイアレクトって公式ドキュメントを始め読んでいた時は何を言っているかわからなかったのですが、要するに、「delimiter
, escapechar
, quotechar
やquoting
などの設定がまとまっていて、writer
やreader
関数の引数に指定することでそれらの設定を適用させることができる」ようなものらしい。
実際に、writer
やreader
のdialect
引数としてデフォルトでは'excel'
というダイアレクトが指定されている。
help(csv.writer)
Output:
Help on built-in function writer in module _csv: writer(...) csv_writer = csv.writer(fileobj [, dialect='excel'] [optional keyword args]) for row in sequence: csv_writer.writerow(row) [or] csv_writer = csv.writer(fileobj [, dialect='excel'] [optional keyword args]) csv_writer.writerows(rows) The "fileobj" argument can be any object that supports the file API.
そこで、'excel'
というダイアレクトにはどのような設定がされているのかを実際に見てみると以下のようになっているのがわかります。
a = csv.excel # excelというダイアレクトのクラスのオブジェクトを作成する
delimiter
などの設定はアトリビュートとして設定されています。
a.delimiter
Output:
','
print(a.escapechar)
Output:
None
a.quotechar
Output:
'"'
a.quoting
Output:
0
なるほど。実際に設定されているようです。
'excel'
以外のダイアレクトとして'excel-tab'
, 'unix_dialect'
があり、自分が扱いたいファイルに応じて選択すればよさそうですね。
終わり
以上で、csvモジュールのまとめを終わりにします。ブログを書き始めて経験が浅いので、表記ゆれや誤字もあると思いますし、そもそもPythonやプログラミングの知識も浅いので、言葉の使い方も正確ではないかもしれませんが、少しでも皆様の役に立てれば幸いです。
- 作者:Bill Lubanovic
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- 作者:柴田 淳
- 発売日: 2016/12/22
- メディア: 単行本