Синтаксис отрицательного просмотра и положительного просмотра вперед

Учитывая следующий текст:

Меня зовут Фу.

Меня зовут бар.

Чтобы вернуть каждую строку, содержащую или не содержащую определенную подстроку, можно использовать как положительные, так и отрицательные шаблоны регулярных выражений для возврата одного и того же результата:

Положительный просмотр вперед: ^(?=.*bar).*$ возвращает My name is bar.

Отрицательный прогноз: ^((?!foo).)*$ возвращает My name is bar.

Однако почему отрицательный прогноз должен быть вложен в несколько наборов круглых скобок с квалификатором . и квантификатором *, разделенными круглыми скобками, тогда как в положительном прогнозе они могут быть смежными .*?


person singularity    schedule 06.04.2016    source источник


Ответы (2)


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

Вместо умеренного жадного токена:

^(?!.*foo).*$

См. демонстрацию регулярного выражения.

Здесь,

  • ^ — соответствует местоположению в начале строки
  • (?!.*foo) - отрицательный просмотр вперед, если совпадение отсутствует, если где-то в строке есть foo (или строка, если включен режим DOTALL)
  • .*$ - любые символы 0+ (но новая строка, если режим DOTALL выключен) до конца строки/строки.

Что использовать?

Закаленный жадный токен обычно намного менее эффективен. Используйте предпросмотр, привязанный в начале, когда вам просто нужно проверить, содержит ли строка что-то или нет. Однако в некоторых случаях может потребоваться умеренный жадный токен. См. Когда использовать этот метод.

person Wiktor Stribiżew    schedule 06.04.2016
comment
Спасибо за дополнительную информацию об умеренных жадных токенах - я не знал, что я делаю. - person singularity; 06.04.2016
comment
На самом деле, я довольно разочарован тем фактом, что знаменитый Регулярное выражение для соответствия строке, которая не содержит слова? лучший ответ останавливается на этом умеренном жадном токене. Это не лучшее решение для этой задачи. Узким местом является незакрепленный просмотр вперед, который выполняется в каждом месте в строке, в то время как в моем ответе просмотр вперед запускается в самом начале, выполняется только один раз. И достаточно посмотреть, есть ли в строке слово или нет. - person Wiktor Stribiżew; 06.04.2016
comment
Хороший реф! Вот именно этот ответ меня и смутил! - person singularity; 06.04.2016

Пример

Учитывая строку text = 'a123b456c', и мы хотим использовать подстроку '123' в качестве привязки

(?=123) Positive lookahead:    Matches substring '123' as a *forward* anchor 
(?<=123) Positive lookbehind:  Matches substring '123' as a *backward* anchor
(?!123) Negative lookahead:    Substring not matching '123' as a *forward* anchor
(?<!123) Negative lookbehind:  Substring not matching '123' as a *backward* anchor

'123' используется только как якорь и не заменяется. Посмотрите, как это работает:

import re 

text = 'a123b456c'

re.sub('a(?=123)', '@', text) # outputs '@123b456c' note '123' not replaced
re.sub('(?<=123)b', '@', text) # outputs 'a123@456c' 
re.sub('b(?!123)', '@', text) # outputs 'a123@456c' since '456' not match '123'
re.sub('(?<!123)c', '@', text) # outputs 'a123b456@' 

Надеюсь это поможет

person Yi Xiang Chong    schedule 29.11.2019