記念すべき(?)初投稿です。
事の起こり
pythonに触れたての初心者なので、ネットの情報を漁りながらcsvライブラリを使い
tsvファイルを取り込む処理を書いていたところ
import csv
import pprint
def loadTsv(filename):
with open(filename, newline='') as f:
reader = csv.reader(f, delimiter='\t')
for row in reader:
pprint.pprint(row)
下記のようなデータに対してパースがうまく行かない現象が発生しました。
0 test 1 hogehoge a b
0 test 1 "fugafuga a c
0 test 1 piyopiyo a b c
自分の中の理想値と発生した問題
自分の中の理想としては下記を想定していたのですが
('0','test','1','hogehoge','a','b','')
('0','test','1','"fugafuga','a','','c')
('0','test','1','hogehoge','a','b','c')
実際には
('0','test','1','hogehoge','a','b','')
('0','test','1','fugafuga\ta\t\tc\t0\ttest\t1\thogehoge\ta\tb\tc')
というように何とも絶望的な形になっていました。。。
delimiterに\tを指定しているのになんでこうなるんだ???と混乱しましたが、結論は簡単なことでした。
問題の原因
Dialect クラスの書式化パラメータ「Dialect.quoting」にて、「csv.QUOTE_MINIMAL」が設定されているため
csv.QUOTE_MINIMAL
writer オブジェクトに対し、 delimiter 、 quotechar または lineterminator に含まれる任意の文字のような特別な文字を含むフィールドだけをクオートするように指示します。
参考: Python公式ドキュメント Dialect.quoting
参考: Python公式ドキュメント QUOTE_MINIMAL
2行目の中で
"fugafuga ...
となっている部分のダブルクォーテーションがクォート対象となり、かつその後閉じられることが無かったため
文末までの全ての\tが無視されることで、問題の結果になっていました。
解決方法
少し乱暴ですが、自分の場合は特にクォートを気遣う必要が無かったため、csv.QUOTE_NONEに書き換えました。
csv.QUOTE_NONE
writer オブジェクトに対し、フィールドを決してクオートしないように指示します。現在の delimiter が出力データ中に現れた場合、現在設定されている escapechar 文字が前に付けられます。 escapechar がセットされていない場合、エスケープが必要な文字に遭遇した writer は Error を送出します。reader に対しては、クオート文字の特別扱いをしないように指示します。
import csv
import pprint
def loadTsv(filename):
with open(filename, newline='') as f:
reader = csv.reader(f, delimiter='\t', quoting=csv.QUOTE_NONE)
for row in reader:
pprint.pprint(row)
csvの常識を考えれば分かるものであった気がします、もっと精進せねば……。