正则表达式负向前看

2024-05-20 01:07:07 发布

您现在位置:Python中文网/ 问答频道 /正文

在我的主目录中,我有一个文件夹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

此命令的作用是gzip文件夹drupal-6.14,不包括drupal-6.14/sites/的所有子文件夹,但包含sites/all和sites/default的子文件夹除外。

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

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

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

使用正则表达式

Match all strings, except those that don't contain subpattern x. Or in other words, negating a subpattern.

我(认为)我知道解决这些问题的一般策略是使用否定的观点,但是我从来没有满意地理解过积极和消极的观点(前/后)是如何工作的。

这些年来,我在上面读了很多网站。PHP和Python regex手册、其他类似http://www.regular-expressions.info/lookaround.html的页面等等,但我从未真正对它们有过深入的了解。

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

--更新一个:

关于Andomar的回答:双否定的lookahead是否可以更简洁地表示为一个正的lookahead语句:

即:

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

相当于:

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

???

——更新二:

根据“andomar”和“alan moore”的说法,你不能把双负展望换成正展望。


Tags: 命令目录文件夹default平台tarallfind
3条回答

Lookarounds可以嵌套。

因此,这个regex匹配“drupal-6.14/”即后跟“sites”即后跟“/all”或“/default”。

困惑?使用不同的词,我们可以说它与“drupal-6.14/”匹配,即不是紧跟“sites”,除非后面紧跟“/all”或“/default”

一个否定的展望说,在这个位置,下面的正则表达式不能匹配。

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

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。嵌套的负lookahead变为正lookahead:Thec应该存在。

在每个示例中,只有a匹配。向前看只是一个条件,不会添加到匹配的文本中。

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

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

?=更改为?!以匹配原始regex只会使这些匹配无效:

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

所以,这仅仅意味着drupal-6.14/现在不能后面跟着sites后面跟着除了/all/default之外的任何东西。现在,这些输入将满足regex:

drupal-6.14/sites/all
drupal-6.14/sites/default
drupal-6.14/sites/all42

但是,从其他一些答案(也可能是您的问题)中可能不明显的是,您的regex还允许其他输入,其中drupal-6.14/后面还有sites以外的任何内容。例如:

drupal-6.14/foo
drupal-6.14/xsites

结论:因此,您的regex基本上说要包含drupal-6.14的所有子目录,除了sites的那些子目录,它们的名称以alldefault以外的任何子目录。

相关问题 更多 >