Я пытаюсь создать варианты строк, применив замену по выбору.Комбинаторный продукт подстановок регулярных выражений
Например, одна схема замещения удаляет любую последовательность пустых символов. Вместо того, чтобы заменить все вхождения, как
>>> 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 (без написания анализатора для интерпретации ссылок на группы)?
Спасибо, это очень хороший намек! Ограничения для вызываемого аргумента можно легко удалить, сделав его общим: во внутреннем цикле замените '... + match.expand (subst)' на '... + subst (match)'. Если аргумент не является вызываемым для начала, просто оберните функцию (в начале кода): 'if not callable (subst): static_subst = subst; subst = lambda m: m.expand (static_subst) ' – lenz