web-dev-qa-db-ja.com

正規表現否定先読み

私のホームディレクトリには、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をgzipし、drupal-6.14/sites /のすべてのサブフォルダーを除くsites/allおよびsites/defaultを除きます。これには含まれます。

私の質問は正規表現にあります:

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

worksは、除外したいすべてのフォルダーを除外しますが、その理由はよくわかりません。

これは、正規表現を使用した一般的なタスクです

do n'tにサブパターンxが含まれる文字列を除く、すべての文字列に一致します。または、言い換えると、サブパターンを無効にします。

私は(これらの問題を解決する一般的な戦略はネガティブな先読みの使用であることを理解していますが、ポジティブとネガティブな先読みがどのように機能するかを満足できるレベルまで理解したことはありません。

長年にわたり、私はそれらに関する多くのウェブサイトを読みました。 PHP and Python正規表現マニュアル、 http://www.regular-expressions.info/lookaround.html のような他のページ等々、しかし、私は決して本当にはそれらをしっかりと理解していませんでした。

誰かが、これがどのように機能しているかを説明し、おそらく同様のことをするいくつかの同様の例を提供できますか?

-アップデート1:

Andomarの応答について:二重の負の先読みは、単一の正の先読みステートメントとしてより簡潔に表現できますか?

つまり:

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

に相当:

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

???

-更新2:

@andomarと@alan mooreによると、二重の負の先読みを正の先読みと交換することはできません。

55

負の先読みは、この位置では、次の正規表現は一致しないと言います。

簡単な例を見てみましょう。

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

最後の例はdouble negationです:bの後にcが続くことを許可します。ネストされた負の先読みは、正の先読みになります。cが存在する必要があります。

各例では、aのみが一致します。先読みは単なる条件であり、一致したテキストには追加されません。

103
Andomar

ルックアラウンドはネストできます。

したがって、この正規表現は、「drupal-6.14 /」、つまりnotの後に「sites」、つまりnotの後に「/ all」または「/ default」が一致します。

紛らわしい?別の単語を使用すると、「drupal-6.14 /」に一致すると言うことができます。これは、notに「sites」が続くnlessに「/ all」または「/」が続くデフォルト"

12
ʞɔıu

このように正規表現を修正する場合:

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//not の後にsitesの後に //allまたは/default以外のものが続くことを意味します。したがって、 these 入力は正規表現を満たします。

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

しかし、他のいくつかの答え(そしておそらくあなたの質問)から明らかでないかもしれないのは、あなたの正規表現がdrupal-6.14/の後にsites以外のものも続く other 入力も許可することです。例えば:

drupal-6.14/foo
drupal-6.14/xsites

結論:つまり、正規表現は基本的に all drupal-6.14のサブディレクトリ except 名前のsitesのサブディレクトリを含めるように言っていますallまたはdefault以外のもので始まります。

2
DavidRR