オプションで置換を適用して文字列バリアントを作成しようとしています。
たとえば、1 つの置換方式では、一連の空白文字を削除します。のようにすべてのオカレンスを置き換えるのではなく、
>>> re.sub(r'\s+', '', 'a b c')
'abc'
– 代わりに、オカレンスごとに 2 つのバリアントを生成する必要があります。置換は一方のバリアントで実行され、もう一方のバリアントでは実行されません。文字列について'a b c'
は、バリアントが必要です
['a b c', 'a bc', 'ab c', 'abc']
すなわち。すべてのバイナリ決定の外積 (結果には明らかに元の文字列が含まれます)。
この場合、バリアントは と を使用して生成できre.finditer
ますitertools.product
。
def vary(target, pattern, subst):
occurrences = [m.span() for m in pattern.finditer(target)]
for path in itertools.product((True, False), repeat=len(occurrences)):
variant = ''
anchor = 0
for (start, end), apply_this in zip(occurrences, path):
if apply_this:
variant += target[anchor:start] + subst
anchor = end
variant += target[anchor:]
yield variant
これにより、上記の例の目的の出力が生成されます。
>>> list(vary('a b c', re.compile(r'\s+'), ''))
['abc', 'ab c', 'a bc', 'a b c']
ただし、このソリューションは固定文字列の置換に対してのみ機能します。同様のグループ参照からの高度な機能はre.sub
、単語内の一連の数字の後にスペースを挿入する次の例のように、そのようには実行できません。
re.sub(r'\B(\d+)\B'), r'\1 ', 'abc123def')
re.sub への有効な引数を受け入れるようにアプローチを拡張または変更するにはどうすればよいでしょうか (グループ参照を解釈するためのパーサーを作成する必要はありません)。