Я пытаюсь создать варианты строк, опционально применяя замены.
Например, одна схема замены удаляет любую последовательность пустых символов. Вместо замены всех вхождений, таких как
>>> re.sub(r'\s+', '', 'a b c')
'abc'
– Вместо этого мне нужно создать два варианта для каждого вхождения, поскольку замена выполняется в одном варианте, а не в другом. Для строки '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 (без написания синтаксического анализатора для интерпретации групповых ссылок)?