假设我有以下几点:
{{你好}你好}{世界{地球}|
{再见|再见}{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()

08-25 21:58