2009-11-17 3 views
40

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

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

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

Что эта команда делает gzips папку Друпал-6.14, исключая все подкаталоги Друпал-6,14/сайтов/за исключением сайтов/все и сайты/по умолчанию, которые он включает.

Мой вопрос о регулярном выражении:

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

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

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

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

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

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

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

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

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

ИЭ:

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

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

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

???

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

По @andomar и @alan МУР - вы не можете поменять местами двойной отрицательный предпросмотр для положительного опережающего просмотра.

ответ

84

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

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

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

+0

Если вложенный негативный взгляд («двойной отрицательный взгляд») может стать положительным взглядом, можно ли представить эквивалент в форме положительного вида? i.e: (a) Какова была бы положительная обратная форма моего двойного отрицательного внешнего вида drupal "'drupal-6.14/(! sites (?!/all |/default)). *'" example? Будет ли это: 'drupal-6.14/(? = Sites/all | default). * ??? (б) Какова была бы положительная обратная форма вашего двойного негативного взгляда "(!? B (?! C))" пример? – themesandmodules

+0

eww. Прости. первый раз, используя комментарии здесь, что форматирование ужасно. плохо отредактируйте вопрос. – themesandmodules

+0

@willieseabrook: Не думайте так, только часть взгляда двойная отрицательная, поэтому вы не можете заменить целое положительным – Andomar

12

Образцы могут быть вложенными.

Так что регулярное выражение соответствует «Друпали-6.14 /», то есть не следует «сайты», то есть не следует «/ все» или «/ по умолчанию».

Confusing?Используя различные слова, мы можем сказать, что это соответствует «Друпал-6,14 /», то есть не следуют «сайты» если что не далее следуют «/ все» или «/ по умолчанию»

+0

Благодарим за это. И * да * Я все еще считаю, что это путает LOL. Я думаю, что вы цитируете «не сопровождаемые сайтами», если только «за ними не следует» по умолчанию ». – themesandmodules

1

Если пересмотреть ваше регулярное выражение как это:

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.