Регулярное выражение отрицательный взгляд - PullRequest
53 голосов
/ 17 ноября 2009

В моем домашнем каталоге у меня есть папка drupal-6.14, которая содержит платформу Drupal.

Из этого каталога я использую следующую команду:

find drupal-6.14 -type f -iname '*' | grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' | xargs tar -czf drupal-6.14.tar.gz

Эта команда делает gzips папку drupal-6.14 , исключая все подпапки drupal-6.14 / sites / , кроме sites / all и sites / default , в который входит.

У меня вопрос к регулярному выражению:

grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*'

Выражение работает для исключения всех папок, которые я хочу исключить, но я не совсем понимаю, почему.

Это обычная задача с использованием регулярных выражений для

Соответствует всем строкам, кроме тех, которые не содержат подшаблон x. Или, другими словами, отрицание подшаблона.

Я (думаю) понимаю, что общей стратегией решения этих проблем является использование негативных взглядов, но я никогда не понимал до удовлетворительного уровня, как работают позитивные и негативные взгляды (впереди / позади).

За эти годы я прочитал много сайтов на них. Руководства по регулярным выражениям PHP и Python, другие страницы, такие как http://www.regular -expressions.info / lookaround.html и т. Д., Но у меня никогда действительно не было четкого понимания их.

Может ли кто-нибудь объяснить, как это работает, и, возможно, привести несколько похожих примеров, которые бы делали подобные вещи?

- Обновление 1:

Относительно ответа Andomar: может ли двойной отрицательный прогноз быть более кратко выражен в виде одного положительного прогнозного заявления:

То есть:

'drupal-6.14/(?!sites(?!/all|/default)).*'

эквивалентно:

'drupal-6.14/(?=sites(?:/all|/default)).*'
* * ??? тысяча сорок-девять

- Обновление два:

Что касается @andomar и @alan moore - вы не можете поменять местами двойной отрицательный взгляд на положительный взгляд.

Ответы [ 3 ]

101 голосов
/ 17 ноября 2009

Отрицательный взгляд говорит, что в этой позиции следующее регулярное выражение не может совпадать.

Давайте рассмотрим упрощенный пример:

a(?!b(?!c))

a      Match: (?!b) succeeds
ac     Match: (?!b) succeeds
ab     No match: (?!b(?!c)) fails
abe    No match: (?!b(?!c)) fails
abc    Match: (?!b(?!c)) succeeds

Последний пример - двойное отрицание : он допускает b, за которым следует c. Вложенный отрицательный взгляд становится положительным взглядом: должен присутствовать c.

В каждом примере сопоставляется только a. Предварительный просмотр является только условием и не добавляет к сопоставленному тексту.

12 голосов
/ 17 ноября 2009

Lookarounds могут быть вложенными.

Так что это регулярное выражение соответствует "drupal-6.14 /", то есть , а не , за которым следуют "сайты", которые не , за которыми следуют "/ all" или "/default".

Смешение? Используя другие слова, мы можем сказать, что он соответствует «drupal-6.14 /», то есть , а не , за которым следуют «сайты» , если только , за которым следуют «/ all» или «/ default»

2 голосов
/ 10 мая 2016

Если вы измените свое регулярное выражение следующим образом:

drupal-6.14/(?=sites(?!/all|/default)).*
             ^^

... тогда он будет соответствовать всем входным данным, которые содержат drupal-6.14/, затем sites, затем что угодно, кроме /all или /default. Например:

drupal-6.14/sites/foo
drupal-6.14/sites/bar
drupal-6.14/sitesfoo42
drupal-6.14/sitesall

Изменение ?= на ?! в соответствии с вашим исходным регулярным выражением просто отменяет эти совпадения:

drupal-6.14/(?!sites(?!/all|/default)).*
             ^^

Таким образом, это просто означает, что drupal-6.14/ сейчас не может сопровождаться sites, сопровождаемым чем-либо отличным от /all или /default. Итак, теперь эти входы будут удовлетворять регулярному выражению:

drupal-6.14/sites/all
drupal-6.14/sites/default
drupal-6.14/sites/all42

Но что может быть неочевидно из некоторых других ответов (и, возможно, вашего вопроса), так это то, что ваше регулярное выражение также разрешит другие входы, где за drupal-6.14/ следует что-то кроме sites также. Например:

drupal-6.14/foo
drupal-6.14/xsites

Вывод: Итак, ваше регулярное выражение в основном говорит, что включает все подкаталоги drupal-6.14 , за исключением тех подкаталогов sites, имя которых начинается с чего-либо другого чем all или default.

...