Python正则表达式:捕获超前值(捕获文本而不消耗它)

时间:2012-04-09 23:16:19

标签: python regex python-3.x lookaround

我希望使用正则表达式将单词分成(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')]

问题是我希望比赛重叠 - 最后一组元音应该成为下一场比赛的第一组。如果我们按如下方式替换正则表达式,那么前瞻性可能会出现这种情况:

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

我们得到:

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

这意味着我们正在匹配我想要的东西。但是,它现在不返回最后一组元音。我想要的输出是:

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

我觉得这应该是可能的(如果正则表达式可以检查第二组元音,我认为没有理由它不能返回它们),但我找不到任何办法超越蛮力方法,在我拥有它们之后循环结果,并将下一个匹配的第一个字符追加到最后一个匹配,并将字符串的最后一个字符追加到最后一个匹配。有没有更好的方法可以做到这一点?

两个可行的方法是捕获前瞻值,或者在捕获值时不消耗匹配上的文本 - 我找不到任何方法。

2 个答案:

答案 0 :(得分:8)

我发布后才发现:

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

在前瞻中添加一对额外的括号意味着它本身就成了捕获。

我觉得这很晦涩且很难找到 - 我不确定是否其他所有人都发现这一点很明显,但希望我所在的其他人在将来更容易发现这一点。

答案 1 :(得分:2)

我不会尝试让正则表达式引擎这样做;我会将字符串拆分为辅音和元音块,然后生成重叠结果。这样,你实际上也不需要破解标记,假设当单词实际上没有或以元音结尾时,''作为“元音”部分是可以的。

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仅包含元音,这仍然会失败,但如果有必要,这会被轻易纠正。)