77

在我的主目录中,我有一个包含 Drupal 平台的文件夹 drupal-6.14。

在此目录中,我使用以下命令:

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等等,但我从来没有真正对它们有过深入的了解。

有人可以解释一下这是如何工作的,也许可以提供一些类似的例子来做类似的事情?

-- 更新一:

关于 Andomar 的回应:双否定前瞻能否更简洁地表示为单个肯定前瞻语句:

即是:

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

相当于:

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

???

-- 更新二:

根据@andomar 和@alan moore - 您不能将双负前瞻互换为正前瞻。

4

3 回答 3

144

负前瞻表示,在此位置,以下正则表达式无法匹配。

让我们举一个简化的例子:

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匹配。前瞻只是一个条件,不会添加到匹配的文本中。

于 2009-11-17T16:13:56.650 回答
14

环视可以嵌套。

所以这个正则表达式匹配“drupal-6.14/”,它后面没有“sites”,后面没有“/all”或“/default”。

令人困惑?使用不同的词,我们可以说它匹配没有跟随“sites”的“drupal-6.14/”,除非它进一步跟随“/all”或“/default”

于 2009-11-17T15:06:35.007 回答
6

如果你像这样修改你的正则表达式:

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

...然后它将匹配所有包含drupal-6.14/后跟的输入,sites后跟 /allor以外的任何内容/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/now后面不能or以外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名称以allor以外的任何其他子目录开头的子目录default

于 2016-05-10T20:41:21.843 回答