置換文字列の代わりに関数を受け入れることもできるre.subnを使用した簡単な方法:
import re
from random import randint
def select(m):
choices = m.group(1).split('|')
return choices[randint(0, len(choices)-1)]
def spinner(s):
r = re.compile('{([^{}]*)}')
while True:
s, n = r.subn(select, s)
if n == 0: break
return s.strip()
最も深い選択肢をすべて置き換えるだけで、選択肢がなくなるまで繰り返します。subn
結果と何個の置換が行われたかのタプルを返します。これは、処理の終了を検出するのに便利です。
私のバージョンの は、ランダムセレクターに固執したいだけなら、よりエレガントなselect()
Bobince のものに置き換えることができます。random.choice()
選択ツリーを構築したい場合は、上記の関数を拡張できますが、現在の場所を追跡するためにグローバル変数が必要になるため、関数をクラスに移動することは理にかなっています。これは単なるヒントです。最初の質問ではなかったので、そのアイデアを開発することはしません。
r.subn(select, s, re.U)
最後に、 Unicode 文字列が必要な場合は使用する必要があることに注意してください( s = u"{...}"
)
例:
>>> s = "{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}"
>>> print spinner(s)
'farewell n3wbz'
編集:無限ループを回避し(指摘してくれたBobinceに感謝)、より効率的にするために置き換えsub
、空の中括弧も抽出するために置き換えました。これにより、不適切な形式のパターンに対してより堅牢になるはずです。subn
{([^{}]+)}
{([^{}]*)}
できるだけ多くの情報を 1 行にまとめたい人向け (個人的にはお勧めしません):
def spin(s):
while True:
s, n = re.subn('{([^{}]*)}',
lambda m: random.choice(m.group(1).split("|")),
s)
if n == 0: break
return s.strip()