0や空白の扱いを決めれるようにしてみた

先日から作成中のCSV→JSON変換プログラムですがCSVに空白が含まれている場合や、値が0の項目をどう扱うのかというオプションを付けてみました。

今、以下のようなCSVファイルがあるとします。

ID,   name,        text,   height, weight, sons, daughters
 1,   夏子,      どうも,    159.8,       ,    2,         1
 2,   秋夫,  こんにちは,    180.3,   78.5,    0,         1
 3,   冬子,       Hello,    163.5,       ,    3,         0

基本的には一行目をキーとし、2行目以降を値とするjsonに変換するのは従来どおりなのですが、上のCSVには空白や0の値が含まれています。そこでこれらの扱いを引数として設定できるようにjson出力部分を改造しました。

def jsonwriter(tFileName, tDict, digitize=True, ignore0=True, ignoreBlank=True, blankToNull=True):
    """write tDict to tFile as json.
       if digitize=True, digitizable values will be done.
       if digitize and ignore0 are both True, 0-value element is not written.
       if ignoreBlank=True, blank string ("") is not written.
       if ignoreBlank=False and blankToNull=True, blank string is written as null.
    """
    
    tFile = codecs.open(tFileName, "w", "utf-8")
    
    tFile.write(u"[\n") #先頭の[
    
    outerComFlg = u"" #2行目以降に改行とコンマを書き込むフラグ
    
    for line in tDict:
        tFile.write(outerComFlg + u" {")
        
        outerComFlg = u",\n"
        
        comFlg = u"" #行内の2要素目以降の先頭にコンマを書き込むフラグ
        
        for i, v in line.iteritems():
            skip = False
            if digitize and bool(re.compile("^\d+(\.\d+)?\Z").match(v)):
                if ignore0 and float(v) == 0:
                    skip = True
            else:
                if ignoreBlank and v == "":
                    skip = True
                elif blankToNull and v == "":
                    v = "null"
                else:
                    v = '\"' + v + '\"'
            
            if not skip:
                tStr = comFlg + u'\"' + i + u'\":' + v
            
                tFile.write(tStr)
            
                comFlg = u","
        
        tFile.write(u"}")
    
    tFile.write(u"\n]")
    
    tFile.close()

digitizeについては先日のエントリで書いた通りです。それ以外に

  • ignore0 値が0の項目を書き出さずにとばす。digitizeがTrueの場合のみ有効。
  • ignoreBlank 値が空の項目を書き出さずにとばす。
  • blankToNull 値が空の項目をnullとして書き出す。ignoreBlankがFalseの場合のみ有効。ignoreBlankがFalseでこの値もFalseの場合は""として書き出される。

という3つのオプションを付けてみました。

デフォルトで上のCSVを書き出すと下のようになります。

[
 {"ID":1,"name":"夏子","text":"どうも","height":159.8,"sons":2,"daughters":1},
 {"ID":2,"name":"秋夫","text":"こんにちは","height":180.3,"weight":78.5,"daughters":1},
 {"ID":3,"name":"冬子","text":"Hello","height":163.5,"sons":3}
]

ignore0、ignoreBlankが共にTrueなので夏子、冬子の体重や冬子の娘の項目は出力されません。jsonを利用するプログラム側に値がない場合は未記入か0であるというルールを用意すればやり取りするデータを小さくすることができそうです。

digitize=False, ignoreBlank=Falseだと

[
 {"ID":"1","name":"夏子","text":"どうも","height":"159.8","weight":null,"sons":"2","daughters":"1"},
 {"ID":"2","name":"秋夫","text":"こんにちは","height":"180.3","weight":"78.5","sons":"0","daughters":"1"},
 {"ID":"3","name":"冬子","text":"Hello","height":"163.5","weight":null,"sons":"3","daughters":"0"}
]

といった感じです。
とりあえず出力部分はこれで完成です。