昨日のエントリの補足+α

2013/2/23追記。
補足の補足になってしまいますがこの記事に関する訂正、補足記事を書きました→文字列がfloat型に変換可能かどうかを確認する正規表現について訂正と補足 - 主にプログラムを勉強するブログ
追記ここまで


昨日のエントリで、ある文字列がfloat型に変換可能かどうかを判別する正規表現として

print bool(re.compile("^\d+\.?\d*\Z").match("3.14")) #True

というのを書いていましたが、これは"50."などの小数点以下に数字がないパターンにもマッチしてしまうので厳密ではなかったです。
"50."のように小数点以下に数字がない場合でもfloat()関数が使えるので問題ないと言えば問題ないのですが、より厳密なパターンを考えてみました。

#変換自体は問題ない
print float("50.") #50.0

"."がきた場合は後に必ず数字がこなければならないように書いてみました。

import re

print bool(re.compile("^\d+(\.\d+)?\Z").match("0")) #True
print bool(re.compile("^\d+(\.\d+)?\Z").match("5")) #True
print bool(re.compile("^\d+(\.\d+)?\Z").match("3.14")) #True
print bool(re.compile("^\d+(\.\d+)?\Z").match("1250.5833")) #True
print bool(re.compile("^\d+(\.\d+)?\Z").match("50.")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("3..1")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("3.1.4")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match(".5")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("..5")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("abc")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("15a")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match("a15")) #False
print bool(re.compile("^\d+(\.\d+)?\Z").match(u"こんにちは")) #False

これで値が整数か小数の場合にのみマッチするように「算数的な」意味でも正しくなったはず・・・。

さて、これを使って先日から作成中のcsvからjsonへの変換プログラムの出力部分で値が整数または小数の場合にはそれを数字のまま出力することもできるように改造しました。

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

digitizeという引数がTrueの場合に

ID,name,text
0,ナツ,どうも
1,アキ,こんにちは

というCSV

[
 {"ID":0,"name":"ナツ","text":"どうも"},
 {"ID":1,"name":"アキ","text":"こんにちは"}
]

と変換されます。
digitizeがFalseの場合はすべて文字列化され

[
 {"ID":"0","name":"ナツ","text":"どうも"},
 {"ID":"1","name":"アキ","text":"こんにちは"}
]

になります。