假设我有以下字符串:
trend = '(A|B|C)_STRING'
我想将其扩展为:
A_STRING
B_STRING
C_STRING
OR条件可以是字符串中的任何位置。即STRING_(A|B)_STRING_(C|D)
将扩展为
STRING_A_STRING_C
STRING_B_STRING C
STRING_A_STRING_D
STRING_B_STRING_D
我还想介绍空条件的情况:
(|A_)STRING
将扩展为:
A_STRING
STRING
这是我到目前为止所尝试的内容:
def expandOr(trend):
parenBegin = trend.index('(') + 1
parenEnd = trend.index(')')
orExpression = trend[parenBegin:parenEnd]
originalTrend = trend[0:parenBegin - 1]
expandedOrList = []
for oe in orExpression.split("|"):
expandedOrList.append(originalTrend + oe)
但这显然不起作用。
使用正则表达式有没有简单的方法呢?
答案 0 :(得分:4)
这是一个非常干净的方式。你会很开心地弄清楚它是如何工作的: - )
def expander(s):
import re
from itertools import product
pat = r"\(([^)]*)\)"
pieces = re.split(pat, s)
pieces = [piece.split("|") for piece in pieces]
for p in product(*pieces):
yield "".join(p)
然后:
for s in ('(A|B|C)_STRING',
'(|A_)STRING',
'STRING_(A|B)_STRING_(C|D)'):
print s, "->"
for t in expander(s):
print " ", t
显示:
(A|B|C)_STRING ->
A_STRING
B_STRING
C_STRING
(|A_)STRING ->
STRING
A_STRING
STRING_(A|B)_STRING_(C|D) ->
STRING_A_STRING_C
STRING_A_STRING_D
STRING_B_STRING_C
STRING_B_STRING_D
答案 1 :(得分:3)
import exrex
trend = '(A|B|C)_STRING'
trend2 = 'STRING_(A|B)_STRING_(C|D)'
>>> list(exrex.generate(trend))
[u'A_STRING', u'B_STRING', u'C_STRING']
>>> list(exrex.generate(trend2))
[u'STRING_A_STRING_C', u'STRING_A_STRING_D', u'STRING_B_STRING_C', u'STRING_B_STRING_D']
答案 2 :(得分:1)
我会这样做以提取组:
def extract_groups(trend):
l_parens = [i for i,c in enumerate(trend) if c == '(']
r_parens = [i for i,c in enumerate(trend) if c == ')']
assert len(l_parens) == len(r_parens)
return [trend[l+1:r].split('|') for l,r in zip(l_parens,r_parens)]
然后,您可以使用itertools.product
评估这些提取组的产品:
expr = 'STRING_(A|B)_STRING_(C|D)'
from itertools import product
list(product(*extract_groups(expr)))
Out[92]: [('A', 'C'), ('A', 'D'), ('B', 'C'), ('B', 'D')]
现在只是把它们拼接回原始表达的问题。我将使用re
:)
#python3.3+
def _gen(it):
yield from it
p = re.compile('\(.*?\)')
for tup in product(*extract_groups(trend)):
gen = _gen(tup)
print(p.sub(lambda x: next(gen),trend))
STRING_A_STRING_C
STRING_A_STRING_D
STRING_B_STRING_C
STRING_B_STRING_D
可能有一种更易读的方式让re.sub
顺序替换迭代中的东西,但这就是我的头脑。
答案 3 :(得分:0)
使用sre_yield
module很容易实现:
>>> import sre_yield
>>> trend = '(A|B|C)_STRING'
>>> strings = list(sre_yield.AllStrings(trend))
>>> print(strings)
['A_STRING', 'B_STRING', 'C_STRING']
<块引用>
sre_yield
的目标是有效地生成可以匹配给定正则表达式的所有值,或者有效地计算可能的匹配... sre_parse
模块内部使用的东西),并根据需要构造链式/重复迭代器。可能会有重复的结果,具体取决于您的输入字符串——这些是 re
未优化的情况。