假设我有以下几点:
{{你好}你好}{世界{地球}|
{再见|再见}{noobs | n3wbz | n00blets}
我想把它变成以下任何一种:
Hello world
Goodbye noobs
Hi earth
farewell n3wbz
// etc.
注意“旋转”语法的嵌套方式。据我们所知,它可能被嵌套在十亿层深的地方。
我可以很容易做到这一点,除非一旦它们像上面的例子一样嵌套,我的正则表达式就会出错,结果也不正确。
有人能用.NET语言或Python来演示一个例子吗?
最佳答案
使用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()
版本可以被使用random.choice()
的Bobince替代,如果您只想坚持使用随机选择器,它会更优雅。如果你想建立一个选择树,你可以扩展上面的函数,但是你需要全局变量来跟踪你在哪里,所以把函数移到一个类中是有意义的。这只是一个暗示,我不会发展这个想法,因为它不是真正的起源问题。最后请注意,如果需要unicode字符串(
r.subn(select, s, re.U)
),应该使用s = u"{...}"
例子:
>>> s = "{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}"
>>> print spinner(s)
'farewell n3wbz'
编辑:用
sub
替换subn
以避免无限循环(感谢Bobince指出),使其更有效;用{([^{}]+)}
替换{([^{}]*)}
以提取空的花括号。这将使它对格式错误的模式更加健壮。对于那些喜欢把尽可能多的东西放在一条线上的人(我个人不鼓励这样做):
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()