さり海馬

Thoughts walk away, blog stays.

文字コードで悩んだ

  1. Oracle データベースにクエリを投げてデータを拾ってくる(SJIS)
  2. 中身を解釈してチケットデータを作る(Unicode)
  3. csv 形式で書き出す(Utf-8)

悩んだのは 1.のところ。

import cx_Oracle

con = cx_Oracle.connect( username/password@DTS )
cur = con.cursor()
reader = cur

for item in reader:
  主処理

ってお約束な処理ですが。この cur イテレータの出力が今の環境だと SJIS 確定*1なので、こいつをなんとか unicode に変換したい。でも reader んところは別のインプットとの共通の切り口になっているので、item に入った中身を後から変換する処理はしたくなかった。

んで苦肉の策。

class UnicodeWrapper( object ):
  def __init( self, cursor, encoding='sjis'):
    self.cursor = cursor
    self.encoding = encoding

  def __iter__( self ):
    return self

  def next( self ):
    row = self.cur.next()
    return[ unicode(str(s), self.encoding) for s in row ]

ってして、上の reader = cur んところを

reader = UnicodeWrapper( cur )

って逃げた。インチキ・イテレータークラスだ(笑)。絶対にもっとスマートなやり方があるはず。cx_Oracle の cursor クラスを継承してステキに作り換えるとかな!

…でも動いたからいいや(重要)。

unicode() のこと

unicode( object,[ encoding] ) は、 encoding を指定しないと「unicodeを出力するstr()」な動作をするけど、encodingを指定しちゃうと、ちょっと動作が違う。ここで少しはまった。

t = (1,2,'俺参上')
result = [unicode(s) for s in t]

はうまくいくけど

t = (1,2,'俺参上')
result = [unicode(s, 'sjis') for s in t]

はコケる。encoding を指定すると、int を str に変換してくれなくなるのだった…。

*1:クライアント側の環境変数NLS...をいじれば適切な文字コードに変換して返してくれるはずなんだけど、別のアプリも動いているのでこれをいじりたくなかった