Регулярные выражения Python: захватить прогнозное значение (захват текста без его использования)

Я хочу использовать регулярные выражения, чтобы разбить слова на группы (vowels, not_vowels, more_vowels), используя маркер, чтобы каждое слово начиналось и заканчивалось гласным.

import re

MARKER = "~"
VOWELS = {"a", "e", "i", "o", "u", MARKER}

word = "dog"

if word[0] not in VOWELS:
    word = MARKER+word

if word[-1] not in VOWELS:
    word += MARKER

re.findall("([%]+)([^%]+)([%]+)".replace("%", "".join(VOWELS)), word)

В этом примере мы получаем:

[('~', 'd', 'o')]

Проблема в том, что я хочу, чтобы совпадения совпадали - последний набор гласных должен стать первым в следующем. Это возможно с помощью lookaheads, если мы заменим регулярное выражение следующим образом:

re.findall("([%]+)([^%]+)(?=[%]+)".replace("%", "".join(VOWELS)), word)

Мы получаем:

[('~', 'd'), ('o', 'g')]

Что означает, что мы соответствуем тому, что я хочу. Однако теперь он не возвращает последний набор гласных. Я хочу получить вывод:

[('~', 'd', 'o'), ('o', 'g', '~')]

Я чувствую, что это должно быть возможно (если регулярное выражение может проверять второй набор гласных, я не вижу причин, по которым оно не может их вернуть), но я не могу найти никакого способа сделать это, кроме метода грубой силы, проходящего через результаты после того, как они у меня есть и добавление первого символа следующего совпадения к последнему совпадению, и последний символ строки к последнему совпадению. Есть ли лучший способ, которым я могу это сделать?

Две вещи, которые сработали бы, это захват значения преднамеренного просмотра или не использование текста совпадения при захвате значения - я также не могу найти никакого способа сделать это.

2 ответа

Решение

Я нашел это сразу после публикации:

re.findall("([%]+)([^%]+)(?=([%]+))".replace("%", "".join(VOWELS)), word)

Добавление дополнительной пары скобок внутри заглядывания означает, что это становится самим захватом.

Я нашел это довольно неясным и трудным для поиска - я не уверен, что все остальные находят это очевидным, но, надеюсь, кому-то другому в моем положении это будет легче в будущем.

Я бы не стал пытаться заставить движок регулярных выражений делать это; Я бы разбил строку на согласные и гласные порции, а затем сгенерировал перекрывающиеся результаты. Таким образом, вам также не нужно взламывать маркеры, если вы согласны с '' как часть "гласного", когда слово фактически не является или не заканчивается гласным.

def overlapping_matches(word):
    pieces = re.split('([^aeiou]+)', word)
    # There are other ways to do this; I'm kinda showing off
    return zip(pieces[:-2], pieces[1:-1], pieces[2:])[::2]

overlapping_matches('dog') # [('', 'd', 'o'), ('o', 'g', '')]

(Это по-прежнему не удается, если word содержит только гласные, но это тривиально исправляется при необходимости.)

Другие вопросы по тегам