У меня есть строки, как и бс. Я хочу извлечь все перекрывающиеся подпоследовательности, где подпоследовательность - это единичное окружение с любым числом bs. Это регулярное выражение, которое я написал:
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}])
не работает. Вместо этого я попытался заменить эту группу положительным прогнозом (?<=[{vowels}]|^|{diphtongues})
, но регулярное выражение не будет принимать разную длину (даже удаление дифтонгов не работает, очевидно, ^
имеет другую длину).
Так что это проблемный случай с рисунком выше:
syllables.findall('æbə')
# ['bə']
# should be: ['æb', 'bə']
Редактировать 2:
Я переключился на использование регулярных выражений, которые позволяют просматривать переменную ширину, что решает проблему. К моему удивлению, он даже кажется быстрее, чем модуль re в стандартной библиотеке. Я все еще хотел бы знать, как заставить это работать с модулем re, все же. (