正则表达式负向前瞻

the*_*les 57 regex lookahead negative-lookahead

在我的主目录中,我有一个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
Run Code Online (Sandbox Code Playgroud)

这个命令的作用是gzips文件夹drupal-6.14,不包括drupal-6.14/sites/ 除了sites/all和sites/default之外的所有子文件夹.

我的问题是关于正则表达式:

grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*'
Run Code Online (Sandbox Code Playgroud)

该表达式可以排除我想要排除的所有文件夹,但我不太明白为什么.

使用正则表达式是一项常见任务

匹配所有字符串,但包含子模式x的字符串除外.或者换句话说,否定子模式.

我(想)我明白解决这些问题的一般策略是使用否定的前瞻,但我从来没有理解到正面和负面的外观(前瞻/后退)是如何工作的.

多年来,我已经阅读了很多网站.PHP和Python正则表达式手册,其他页面,如http://www.regular-expressions.info/lookaround.html等,但我从来没有真正理解它们.

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

- 更新一:

关于Andomar的回应:双重否定前瞻可以更简洁地表达为单一的积极前瞻性陈述:

即是:

'drupal-6.14/(?!sites(?!/all|/default)).*'
Run Code Online (Sandbox Code Playgroud)

相当于:

'drupal-6.14/(?=sites(?:/all|/default)).*'
Run Code Online (Sandbox Code Playgroud)

???

- 更新二:

根据@andomar和@alan moore - 你不能互换双负前瞻以获得积极的前瞻.

And*_*mar 105

负向前瞻说,在这个位置,以下正则表达式无法匹配.

我们来看一个简化的例子:

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
Run Code Online (Sandbox Code Playgroud)

最后一个例子是双重否定:它允许a b后跟c.嵌套的否定前瞻变为积极的先行:c应该存在.

在每个示例中,仅a匹配.前瞻只是一个条件,不会添加到匹配的文本中.


ʞɔı*_*ɔıu 12

Lookarounds可以嵌套.

所以这个正则表达式匹配"Drupal的6.14 /"是不是后面是"地王" 跟着"/ all"或"/默认".

混乱?使用不同的单词,我们可以说它匹配"drupal-6.14 /",后面没有 "sites",除非后面跟着"/ all"或"/ default"


Dav*_*dRR 5

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

drupal-6.14/(?=sites(?!/all|/default)).*
             ^^
Run Code Online (Sandbox Code Playgroud)

...然后它将匹配包含drupal-6.14/后跟sites后跟 /allor之外任何内容的所有输入/default。例如:

drupal-6.14/sites/foo
drupal-6.14/sites/bar
drupal-6.14/sitesfoo42
drupal-6.14/sitesall
Run Code Online (Sandbox Code Playgroud)

更改?=?!匹配您的原始正则表达式只会否定这些匹配:

drupal-6.14/(?!sites(?!/all|/default)).*
             ^^
Run Code Online (Sandbox Code Playgroud)

所以,这只是意味着drupal-6.14/now后面不能or之外sites任何内容 。所以现在,这些输入将满足正则表达式:/all/default

drupal-6.14/sites/all
drupal-6.14/sites/default
drupal-6.14/sites/all42
Run Code Online (Sandbox Code Playgroud)

但是,从其他一些答案(也可能是您的问题)中可能不明显的是,您的正则表达式还将允许其他输入,其中drupal-6.14/后面跟有除此之外的任何内容sites。例如:

drupal-6.14/foo
drupal-6.14/xsites
Run Code Online (Sandbox Code Playgroud)

结论:因此,您的正则表达式基本上是说包含 的所有子目录,drupal-6.14 除了sites名称以allor以外的任何内容开头的子目录default