Регулярное выражение отрицательного просмотра вперед

В моем домашнем каталоге есть папка 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

Эта команда сжимает папку 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 и т. д., но я никогда по-настоящему не понимал их.

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

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

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

i.e Is:

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

эквивалент:

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

???

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

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


person themesandmodules    schedule 17.11.2009    source источник


Ответы (3)


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

Возьмем упрощенный пример:

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. Предварительный просмотр - это только условие и не добавляет к совпадающему тексту.

person Andomar    schedule 17.11.2009
comment
Если вложенный отрицательный просмотр вперед (двойной отрицательный просмотр вперед) может стать положительным взглядом вперед, можно ли указать эквивалент в форме положительного просмотра? то есть: (a) Какой была бы форма положительного просмотра вперед в моем примере с двойным отрицательным прогнозом drupal 'drupal-6.14 / (?! sites (?! / all | / default)). *'? Было бы это: 'drupal-6.14 / (? = Sites / all | default). * ??? (b) Какой была бы форма положительного просмотра вперед в вашем примере с двойным отрицательным прогнозом (!? b (?! c))? - person themesandmodules; 24.11.2009
comment
фу. извиняюсь. впервые использую здесь комментарии, что форматирование ужасно. Плохо переформулируйте, отредактировав вопрос. - person themesandmodules; 24.11.2009
comment
@willieseabrook: Не думаю, только часть опережающего просмотра имеет двойное отрицательное значение, поэтому вы не можете заменить целое положительным - person Andomar; 24.11.2009
comment
Просто к вашему сведению, в регулярных выражениях было несколько опечаток; отрицательный прогноз всегда (?!...), а не (!?...). - person Alan Moore; 24.11.2009
comment
У меня была проблема с негативным прогнозом, и ваше заявление на этой позиции прояснило, что я делал неправильно. Благодарю. - person just mike; 23.02.2011
comment
Любая идея, почему это не работает в R. Я получаю ошибку в grep (a (?! B (?! C)), a) Недопустимое регулярное выражение - person pssguy; 09.03.2012

Поисковые запросы могут быть вложенными.

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

Сбивает с толку? Используя другие слова, мы можем сказать, что он соответствует "drupal-6.14 /", который не, за которым следует "сайты" , если за ним не следует "/ all" или "/". дефолт"

person ʞɔıu    schedule 17.11.2009
comment
Спасибо за это. И да я все еще сбиваю с толку LOL. Я думаю, вы цитируете сайты, за которыми не следуют , если только за которыми следует все | default, очень полезно. - person themesandmodules; 24.11.2009

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

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 .

person DavidRR    schedule 10.05.2016