msizの日記

ソフトウェア関係の覚え書きが中心になる予定

python の csv.reader で日本語(encoding指定)

python2.7ではcsvモジュールが標準で使えるけど、日本語関係ではまったので、メモ。

CSVファイルを「codecs.open」などでunicode型で読み込んでも、csv.readerでnext()すると、unicode型でなくなって、色々と文字コード関係のエラーになる。

test.csvの中身(UTF-8)

  "a", "あいう", "123"
  "b", "かきく", "987"

pythonの例::

import codecs, csv

csv_reader = csv.reader(codecs.open("test.csv", encoding="utf-8"))
# ここで、unicode型でなくなる
# sys.getdefaultencoding()がasciiとかだと、コンソール表示
# しようとした時などに日本語でエラー
rows = csv.next()

encoding指定できるcsv.readerっぽいクラスを作りました。使い方はcsv.readerとかとだいたい一緒。

*1

class UnicodeCsvReader:
  """csv.reader wrapper which decodes each value with designated encoding"""
  def __init__(self, iterable, dialect='excel', encoding="utf-8", *args, **kwds):
    self.reader = csv.reader(iterable, dialect=dialect, *args, **kwds)
    self.encoding = encoding
    self.dialect = self.reader.dialect
    self.line_num = 0
  def __iter__(self):
    return self
  def decode(self, value):
      return value and value.decode(self.encoding) or value
  def next(self):
    # csv.reader.next returns a list of values of next row
    cols = [ self.decode(x) for x in self.reader.next() ]
    self.line_num = self.reader.line_num
    return cols

class UnicodeCsvDictReader(csv.DictReader):
    def __init__(self, f, fieldnames=None, restkey=None, restval=None,
                 dialect="excel", encoding="utf-8", *args, **kwds):
        csv.DictReader.__init__(
            self, f, fieldnames, restkey, restval, dialect, *args, **kwds)
        self.encoding = encoding
        self.reader = UnicodeCsvReader(f, encoding=encoding)

参考にしたページです。


関係ないけど、前回のsoftetherのSlackBuild、色々と稚拙ですね。SLCKFLAGSを設定だけして、使ってないとか。
まぁ、SlackBuild使うような人なら、気になるところは自分で何とかすると思うので、そのままにします。

*1:UnicodeReaderに__iter_メソッドが抜けていたので追加しました。