正则表达式负向前瞻

问题描述 投票:0回答:3

在我的主目录中,有一个文件夹 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 进行 gzip 压缩,排除 drupal-6.14/sites/ 的所有子文件夹,除了其包含的 site/all 和sites/default

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

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

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

使用正则表达式来完成任务

匹配所有字符串,除了那些包含子模式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 - 你不能将双负前瞻互换为正前瞻。

regex regex-lookarounds
3个回答
201
投票

负向前瞻表示,在此位置,以下正则表达式不得匹配。

我们举一个简单的例子:

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


15
投票

Lookarounds 可以嵌套。

所以这个正则表达式匹配“drupal-6.14/”,即not,后跟“sites”,即not,后跟“/all”或“/default”。

令人困惑?使用不同的单词,我们可以说它匹配“drupal-6.14/”,即not后跟“sites”unless,再后跟“/all”或“/default”


9
投票

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

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

但是,从其他一些答案(可能还有你的问题)中可能不明显的是,你的正则表达式也将允许 other 输入,其中

drupal-6.14/
后面也跟着
sites
以外的任何内容。例如:

drupal-6.14/foo
drupal-6.14/xsites

结论: 所以,你的正则表达式基本上是说包含 drupal-6.14

all
子目录 除了 那些名称以
sites
all
以外的内容开头的
default
子目录。

© www.soinside.com 2019 - 2024. All rights reserved.