title: Regular expression negative lookahead
body: <p>In my home directory I have a folder drupal-6.14 that contains the Drupal platform.</p>
  
  <p>From this directory I use the following command:</p>
  
  <pre><code>find drupal-6.14 -type f -iname '*' | grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' | xargs tar -czf drupal-6.14.tar.gz
  </code></pre>
  
  <p>What this command does is gzips the folder <em>drupal-6.14</em>, excluding all subfolders of <em>drupal-6.14/sites/</em> <strong>except sites/all and sites/default</strong>, which it includes.</p>
  
  <p>My question is on the regular expression:</p>
  
  <pre><code>grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*'
  </code></pre>
  
  <p>The expression <strong>works</strong> to exclude all the folders I want excluded, but I don't quite understand why.</p>
  
  <p>It is a common task using regular expressions to</p>
  
  <blockquote>
    <p>Match all strings, except those that <strong>don't</strong> contain subpattern x. Or in other words, negating a subpattern.</p>
  </blockquote>
  
  <p>I (think) I understand that the general strategy to solve these problems is the use of negative lookaheads, but I've never understood to a satisfactory level how positive and negative look(ahead/behind)s work.</p>
  
  <p>Over the years, I've read many websites on them. The PHP and Python regex manuals, other pages like <a href="http://www.regular-expressions.info/lookaround.html" rel="noreferrer">http://www.regular-expressions.info/lookaround.html</a> and so forth, but I've never <strong>really</strong> had a solid understanding of them.</p>
  
  <p>Could someone explain, how this is working, and perhaps provide some similar examples that would do similar things?</p>
  
  <p>-- Update One:</p>
  
  <p>Regarding Andomar's response: can a double negative lookahead be more succinctly expressed as a single positive lookahead statement:</p>
  
  <p>i.e Is: </p>
  
  <pre><code>'drupal-6.14/(?!sites(?!/all|/default)).*'
  </code></pre>
  
  <p>equivalent to:</p>
  
  <pre><code>'drupal-6.14/(?=sites(?:/all|/default)).*'
  </code></pre>
  
  <p>???</p>
  
  <p>-- Update Two:</p>
  
  <p>As per @andomar and @alan moore - you can't interchange double negative lookahead for positive lookahead. </p>