我有一连串的as和bs。我想提取所有重叠的子序列,其中一个子序列是由任意数量的b包围的单个a。这是我写的正则表达式:
import re
pattern = """(?= # inside lookahead for overlapping results
(?:a|^) # match at beginning of str or after a
(b* (?:a) b*) # one a between any number of bs
(?:a|$)) # at end of str or before next a
"""
a_between_bs = re.compile(pattern, re.VERBOSE)
它似乎按预期工作,除非字符串中的第一个字符是a,在这种情况下,会丢失以下子序列:
a_between_bs.findall("bbabbba")
# ['bbabbb', 'bbba']
a_between_bs.findall("abbabb")
# ['bbabb']
我不明白发生了什么事。如果我改变潜在匹配的开始顺序,结果也会改变:
pattern = """(?=
(?:^|a) # a and ^ swapped
(b* (?:a) b*)
(?:a|$))
"""
a_between_bs = re.compile(pattern, re.VERBOSE)
a_between_bs.findall("abbabb")
# ['abb']
我本以为这是对称的,所以以a结尾的字符串也可能会丢失,但事实似乎并非如此。怎么回事?你知道吗
编辑:
我假设上述玩具示例的解决方案将转化为我的全部问题,但事实似乎并非如此,因此我现在正在详细说明(对此表示抱歉)。我试图从转录的单词中提取“音节”。“音节”是元音或双元音,前面和后面有任意数量的辅音。这是我提取它们的正则表达式:
vowels = 'æɑəɛiɪɔuʊʌ'
diphtongues = "|".join(('aj', 'aw', 'ej', 'oj', 'ow'))
consonants = 'θwlmvhpɡŋszbkʃɹdnʒjtðf'
pattern = f"""(?=
(?:[{vowels}]|^|{diphtongues})
([{consonants}]* (?:[{vowels}]|{diphtongues}) [{consonants}]*)
(?:[{vowels}]|$|{diphtongues})
)
"""
syllables = re.compile(pattern, re.VERBOSE)
有点棘手的是,双音节以辅音(j或w)结尾,我不想在下一个音节中包含这些辅音。因此,用双负(?<![{consonants}])
替换第一个非捕获组是行不通的。我试着用一个正向的lookahead (?<=[{vowels}]|^|{diphtongues})
来替换这个组,但是regex不会接受不同的长度(即使删除diphlugues也不起作用,显然^
的长度不同)。你知道吗
这就是上述模式的问题所在:
syllables.findall('æbə')
# ['bə']
# should be: ['æb', 'bə']
编辑2: 我已经改用regex,它允许可变宽度lookbehinds,这就解决了这个问题。令我惊讶的是,它甚至比标准库中的re模块还要快。不过,我还是想知道如何让这个模块和re模块一起工作。(:
我建议用双重否定来解决这个问题:
参见regex demo
注意我用lookarounds替换了分组结构:
(?:a|^)
替换为(?<![^a])
,(?:a|$)
替换为(?![^a])
。后者并不重要,但第一个在这里非常重要。你知道吗外部lookahead模式开头的
(?:a|^)
与字符串的a
或开头匹配,无论哪个先到。如果a
在开始处,那么它是匹配的,当输入是abbabb
时,您会得到bbabb
,因为它匹配捕获组模式,并且后面有一个字符串结束位置。下一次迭代在第一个a
之后开始,并且找不到任何匹配项,因为字符串中只剩下的a
在b
之后没有a
注意order of alternative matters。如果更改为
(?:^|a)
,则匹配从字符串的开头开始,b*
匹配空字符串,ab*
获取abbabb
中的第一个abb
,并且由于紧随其后的是a
,因此将abb
作为匹配。无法匹配第一个a
之后的任何内容。你知道吗记住python“短路”,所以,如果它匹配“^”,就不会继续查看它是否也匹配“a”。这将“消耗”匹配字符,因此在匹配“a”的情况下,“a”将被消耗并且不可用于下一个要匹配的组,并且因为使用(?)?:)语法是非捕获的,即“a”是“丢失的”,并且不能被下一个分组捕获(b*(?:a)b*),而当第一个分组使用“^”时,第一个“a”将在第二个分组中匹配。你知道吗
相关问题 更多 >
编程相关推荐