Позитивный и негативный просмотр в регулярках Python
Иногда нужно решить задачу такого типа:
найти строку 'aaa'
и заменить ее
на '!'
, но только если после
'aaa'
стоит 'x'
, а сам
'x'
при этом не заменять. Если мы
попытаемся решить задачу 'в лоб'
,
то у нас ничего не выйдет:
txt = 'aaax baaa'
res = re.sub('aaax', '!', txt)
print(res) # выведет '! baaa', а хотели '!x baaa'
Просмотр вперед
Для решения задачи нужен способ сказать,
что 'x'
не следует заменять. Делается
это с помощью специальных скобок (?= )
,
которые просто смотрят, но не забирают с
собой.
Эти скобки называются позитивный просмотр
вперед. Позитивный - так как 'x'
(в нашем случае) должен быть - только тогда
произойдет замена.
Давайте применим эти скобки для решения нашей задачи:
txt = 'aaax baaa'
res = re.sub('aaa(?=x)', '!', txt)
print(res) # выведет '!x aaab
Есть и негативный просмотр вперед
- (?! )
- он, наоборот, говорит,
что чего-то должно не быть. В следующем
примере, замена произойдет, только если
после 'aaa'
стоит НЕ 'x'
:
txt = 'aaax aaab'
res = re.sub('aaa(?!x)', '!', txt)
print(res) # выведет 'aaax !b'
Просмотр назад
Аналогичным образом есть позитивный
просмотр назад - (?<= )
. В
следующем примере замена произойдет, только
если перед 'aaa'
стоит 'x'
:
txt = 'xaaa'
res = re.sub('(?<=x)aaa', '!', txt)
print(res) # выведет 'x!'
И есть также негативный просмотр назад
- (?<! )
. В следующем примере
замена произойдет, только если перед
'aaa'
не стоит 'x'
:
txt = 'baaa'
res = re.sub('(?<!x)aaa', '!', txt)
print(res) # выведет 'b!'
Практические задачи
Дана строка, содержащая имена функций:
txt = 'func1() func2() func3()'
Получите массив имен функций из строки.
Дана строка с тегом:
txt = '<a href="" class="eee" id="zzz">'
Получите массив имен атрибутов этого тега.
Дана строка с переменными:
txt = '$aaa $bbb $ccc xxxx'
Получите подстроки, перед которыми стоит символ доллара.