让我说我有以下几点:
{{Hello | Hi | Hey} {world | earth} | {再见|告别} {noobs | n3wbz | n00blets}}
我希望这可以变成以下任何一种:
Hello world
Goodbye noobs
Hi earth
farewell n3wbz
// etc.
注意嵌套“旋转”语法的方式。对于我们所知道的,它可以嵌套十亿层深。
我可以很容易地做到这一点,除非他们像上面的例子一样嵌套我的正则表达式混乱并且结果不正确。
有人可以在.NET语言或Python中显示示例吗?
答案 0 :(得分:5)
使用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()
答案 1 :(得分:4)
应该相当简单,只是禁止括号组包含另一个,然后反复调用从内部匹配向外做替换:
def replacebrace(match):
return random.choice(match.group(1).split('|'))
def randomizebraces(s):
while True:
s1= re.sub(r'\{([^{}]*)\}', replacebrace, s)
if s1==s:
return s
s= s1
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Hey world'
>>> randomizebraces('{{Hello|Hi|Hey} {world|earth}|{Goodbye|farewell} {noobs|n3wbz|n00blets}}')
'Goodbye noobs'
答案 2 :(得分:2)
此regex inverter使用pyparsing生成匹配的字符串(有一些限制 - 不允许使用+和*等无限重复符号)。如果用{}代替{},使原始字符串成为正则表达式,逆变器会生成以下列表:
Helloworld
Helloearth
Hiworld
Hiearth
Heyworld
Heyearth
Goodbyenoobs
Goodbyen3wbz
Goodbyen00blets
farewellnoobs
farewelln3wbz
farewelln00blets
(我知道这些空格已经崩溃了,但是这段代码可能会给你一些如何解决这个问题的想法。)
答案 3 :(得分:1)
我会使用re.finditer并构建一个基本的解析树来确定嵌套级别。为此,我将使用正则表达式匹配对象的span属性:
text = '{{Hello|Hi|Hey} {world|earth} | {Goodbye|farewell} {noobs|n3wbz|n00blets}}'
import re
re_bracks = re.compile(r'{.+?}')
# subclass list for a basic tree datatype
class bracks(list):
def __init__(self, m):
self.m = m
# icky procedure to create the parse tree
# I hate these but don't know how else to do it
parse_tree = []
for m in re_bracks.finditer(text):
if not this_element:
# this first match
parse_tree.extend(element(m))
else:
# ... and all the rest
this_element = bracks(m)
this_start, this_end = m.span()
# if this match is nested in the old one ...
if this_start < previous_start and this_end > previous_end:
# nest it inside the previous one
previous_element.extend(this_element)
else:
# otherwise make it a child of the parse_tree
parse_tree.extend(element(m))
previous_element = this_element
previous_start, previous_end = this_start, this_end
这将为您提供括号表达式的嵌套深度。为管道添加一些类似的逻辑,你就可以很好地解决问题了。
答案 4 :(得分:1)