Регулярные выражения 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
содержит только гласные, но это тривиально исправляется при необходимости.)