俺々フォーマットからディクショナリを作る
ここでいう俺々フォーマットとは、好きな書式を自由に作れるというのではなくて、僕が勝手に決めたフォーマットからという意味です。なので汎用性はありません。
GAEで複数のTwitter Botを動かしていて、ほとんどの部分が共通しているから
ボットの名前、行動の名前、呼び出すメソッド、引数
こういう感じのエンティティをデータストアに保存しておいて、ボットの名前からクラスを、行動の名前からメソッドを呼び出す。その時に引数をディクショナリに変換して渡したい。というのが発端です。
具体的には引数文字列が、
source=hoge.txt,is_random,fmt="${item0}, ${item0}!",is_sustainable
こういう感じなら、hoge.txt(区切り文字で区切られたテキスト)をランダムに並び替えて(is_random)、重複しないように投稿した内容を記憶しながら(is_sustainable)、 fmt の形式(テンプレート)で Twitter に投稿する。というような感じで、 is_random を消せば順番に投稿するし、source を変えればつぶやく内容が変わる。フォーマットも自由に変えられる。と、こうしておけば単純な Bot ならプログラムを書かなくても良くなるはず。
単純なBotたち
こういうことがしたい
- 文字列からディクショナリを作る。
- それぞれの要素はカンマで区切られている。
書いてみた
考えた方法は以下の二通り
カンマ区切りで分割する方法は試行錯誤したのですが、僕には出来ませんでした。”クォートされていないカンマ”という正規表現の書き方が分からなかった。トークンごとに取得する方法は、それなりに動いていて、上に書いた引数文字列なら
source="hoge.txt"
fmt="${item0}, ${item0}!"
is_sustainable="True"
is_random="True"
こういう感じのディクショナリが作成されます。
Pythonは名前付きキャプチャというのが使えて便利ですねー。
(?P<hogehoge>pattern)
と書けば、正規表現 pattern にマッチする要素が match.group("hogehoge") で取得できます。match.group("\1") よりも断然わかりやすい!
#!/usr/bin/env python # -*- coding: utf-8 -*- import re def eatup(line): rx_token = re.compile(r'''(?P<KEY>[a-zA-Z_]\w*)=(?P<VAL>("|').*?\3(?=\s*,)|[^,]*)|(?P<FLG>[a-zA-Z_]\w*)''') rx_quote = re.compile(r'''^(['"])(.*)\1$''') result = {} while line: m = rx_token.match(line) if m: if m.group("FLG"): result[m.group("FLG")] = True else: key = m.group("KEY").strip() value = m.group("VAL").strip() result[key] = rx_quote.sub(r"\2", value) line = line[m.end():].lstrip() else: if line[0] != ",": raise SyntaxError, "invalid syntax" line = line[1:].lstrip() return result if __name__ == '__main__': data = u"""source=hoge.txt,is_random,fmt="${item0}, ${item0}!",is_sustainable""" for k, v in eatup(data).iteritems(): print '%s="%s"' % (k, v)