Hatena::ブログ(Diary)

Pashango’s Blog このページをアンテナに追加 RSSフィード

2011-04-07

文字列のcsvを解析する方法

csvモジュールはcsvファイルしか解析できないと思われがちだが、メモリ上のcsvを解析する事も可能。

一番簡単な方法は、以下の通り。

import csv
for row in csv.reader(['one,two,three']):
    print row
# ['one', 'two', 'three']

複数行の文字列も解析可能。

import csv

csv_str = """
one,two,three
four,five,six
"""

for row in csv.reader(csv_str.strip().splitlines()):
    print row
#['one', 'two', 'three']
#['four', 'five', 'six']

但し上の方法だと、フィールドが複数行の場合は改行が削除されてしまう。

改行を保持したまま解析したい場合はStringIOを使う。

import csv

csv_str = """
one,two,three
four,five,"six
seven"
"""

for row in csv.reader(csv_str.strip().splitlines()):
    print row
# Bad
#['one', 'two', 'three']
#['four', 'five', 'sixseven']

#改行を保持したい場合は、StringIOを使う
import StringIO

for row in csv.reader(StringIO.StringIO(csv_str.strip())):
    print row
# Good
#['one', 'two', 'three']
#['four', 'five', 'six\nseven']

小技

Excelからセルをコピペするとタブ区切りになる。

タブ区切りに対応する場合はcsv.reader()の第2引数csv.excel_tabを指定すると簡単。

import csv
import StringIO

csv_str = """
one\ttwo\tthree
four\tfive\tsix
"""

for row in csv.reader(StringIO.StringIO(csv_str.strip()), csv.excel_tab):
    print row

おまけ

csv.Sniffer.sniff()を使うと、csvの区切り文字などをpythonが推測してくれる。

外部のCSVの形式が不定の場合に使えるかも。

import csv
import StringIO

csv_str = """
one\ttwo\tthree
four\tfive\tsix
"""

io = StringIO.StringIO(csv_str.strip())

try:
    #サンプルを元に区切り文字を推測する
    dialect = csv.Sniffer().sniff(io.readline())
except:
    dialect = csv.excel

io.seek(0)
for row in csv.reader(io, dialect):
    print row
#タブ区切りだと推測成功
#['one', 'two', 'three']
#['four', 'five', 'sixseven']

区切り文字がある程度決まっている場合は、sniff()の第2引数に区切り文字の候補を与えてあげると精度が上がる。

# 区切り文字がタブかカンマの2択の場合は以下の通り
dialect = csv.Sniffer().sniff(io.readline(), "\t,")

ヘッダ行があるか推測するcsv.Sniffer.has_header()もあるらしい。

注意点

マニュアルより、Unicodeはサポートしていないそうです。

ノート

このバージョンの csv モジュールは Unicode 入力をサポートしていません。また、現在のところ、 ASCII NUL 文字に関連したいくつかの問題があります。従って、安全を期すには、全ての入力を UTF-8 または印字可能な ASCII にしなければなりません。これについては 使用例 節の例を参照してください。これらの制限は将来取り去られることになっています。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/pashango_p/20110407/1302170999