Выражение регулярного выражения Python для удаления дефисов между строчными символами - PullRequest
0 голосов
/ 15 мая 2018

Мне нужно удалить дефисы только между строчными буквами.Это выражение, которое у меня есть в данный момент:

re.sub('\[a-z]-\[a-z]', "", 'hyphen-ated Asia-Pacific 11-12')

Я хочу, чтобы оно вернулось:

'hyphenated Asia-Pacific 11-12'

Ответы [ 3 ]

0 голосов
/ 15 мая 2018

Два подхода, включая некоторое время:

import re, timeit

def a1():
    s = re.sub(r'([a-z])-([a-z])', r'\1\2', "hyphen-ated Asia-Pacific 11-12")

def a2():
    s = re.sub(r'(?<=[a-z])-(?=[a-z])', '', "hyphen-ated Asia-Pacific 11-12")

print(timeit.timeit(a1, number = 10**5))
print(timeit.timeit(a2, number = 10**5))

Урожайность

0.9709542730015528
0.37731508900105837

Итак, в этом случае обходные пути могут быть быстрее.

0 голосов
/ 15 мая 2018

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'

Это также дает правильный ответ. Теперь мы просто сопоставляем дефис, но настаиваем на том, чтобы ему предшествовал и сопровождался строчной буквой. Поскольку совпадение является только дефисом, строка замены может быть пустой.

Иногда использование вида сзади позволяет ускорить матч. Иногда это замедляет это. Всегда важно делать тесты с определенным шаблоном, если скорость имеет значение для вас. Но первая задача - правильно подобрать матч.

0 голосов
/ 15 мая 2018
re.sub(r'([a-z])-([a-z])', r'\1\2', "hyphen-ated Asia-Pacific 11-12")

Захватывает буквы до и после дефиса и сохраняет их при удалении дефиса. \1 и \2 обозначают первую и вторую захваченную группу, которые в данном случае являются буквами.

Ваш текущий код соответствует двум буквам вокруг дефиса и удаляет все совпадение. Вы должны сохранить буквы при замене.

...