TL; DR:
>>> re.sub('([a-z])-(?=[a-z])', r'\1', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'
или
>>> re.sub('(?<=[a-z])-(?=[a-z])', '', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'
Основным усложнением контекстной замены («найти все дефисы, окруженные строчными буквами») является то, что конечный контекст (часть, следующая за шаблоном для сопоставления) не должен быть включен в совпадение. Если это так, он не сможет участвовать в следующем матче.
Пример, вероятно, прояснит это.
Наивным решением будет
>>> re.sub('([a-z])-([a-z])', r'\1\2', 'hyphen-ated Asia-Pacific 11-12')
'hyphenated Asia-Pacific 11-12'
, который отличается от вызова в вопросе, потому что он соответствует строчным буквам вокруг дефиса, захватывая их, чтобы их можно было вставить в результат. В этом случае единственной подстрокой, соответствующей шаблону, была n-a
, и она была правильно заменена на na
.
Но предположим, что у нас было два дефиса ближе друг к другу, например:
>>> re.sub('([a-z])-([a-z])', r'\1\2', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obliga-tory hyphenated Asia-Pacific 11-12'
a
был частью совпадения g-a
, и поиск возобновился с -
после a
. Поэтому он никогда не видел шаблон a-t
, который бы соответствовал.
Чтобы решить эту проблему, мы можем использовать прогнозное утверждение :
>>> re.sub('([a-z])-(?=[a-z])', r'\1', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'
Теперь конечный контекст (строчная буква после дефиса) не является частью совпадения, и, следовательно, нам не нужно повторно вставлять его в замену. Это означает, что после сопоставления g-
с завершающим a
поиск возобновляется, начиная с a
, и следующее совпадение будет a-
с завершающим t
.
Python также может делать «lookbehinds», в котором шаблон соответствует, только если ему предшествует другой шаблон. Используя как взгляд назад, так и взгляд вперед, мы могли бы написать:
>>> re.sub('(?<=[a-z])-(?=[a-z])', '', 'oblig-a-tory hyphen-ated Asia-Pacific 11-12')
'obligatory hyphenated Asia-Pacific 11-12'
Это также дает правильный ответ. Теперь мы просто сопоставляем дефис, но настаиваем на том, чтобы ему предшествовал и сопровождался строчной буквой. Поскольку совпадение является только дефисом, строка замены может быть пустой.
Иногда использование вида сзади позволяет ускорить матч. Иногда это замедляет это. Всегда важно делать тесты с определенным шаблоном, если скорость имеет значение для вас. Но первая задача - правильно подобрать матч.