Reguliere uitdrukking negatieve vooruitblik

In mijn homedirectory heb ik een map drupal-6.14 die het Drupal-platform bevat.

Vanuit deze map gebruik ik het volgende commando:

find drupal-6.14 -type f -iname '*' | grep -P 'drupal-6.14/(?!sites(?!/all|/default)).*' | xargs tar -czf drupal-6.14.tar.gz

Wat dit commando doet is de map drupal-6.14 gzippen, met uitzondering van alle submappen van drupal-6.14/sites/ behalve sites/all en sites/default , die het bevat.

Mijn vraag gaat over de reguliere expressie:

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

De uitdrukking werkt om alle mappen uit te sluiten die ik wil uitsluiten, maar ik begrijp niet helemaal waarom.

Het is een veelvoorkomende taak om reguliere expressies te gebruiken om

Overeenkomen met alle tekenreeksen, behalve die geen subpatroon x bevatten. Of met andere woorden, een subpatroon ontkennen.

Ik (denk) dat ik begrijp dat de algemene strategie om deze problemen op te lossen het gebruik van negatieve vooruitblik is, maar ik heb nooit tot een bevredigend niveau begrepen hoe positieve en negatieve vooruit-/achteruitkijken werken.

>

In de loop der jaren heb ik er veel websites over gelezen. De PHP en Python regex handleidingen, andere pagina’s zoals http://www.regular-expressions.info/lookaround .html enzovoort, maar ik heb er nog nooit echt een goed begrip van gehad.

Kan iemand uitleggen hoe dit werkt, en misschien enkele vergelijkbare voorbeelden geven die vergelijkbare dingen zouden doen?

— Een update:

Wat betreft de reactie van Andomar: kan een dubbele negatieve vooruitblik beknopter worden uitgedrukt als een enkele positieve vooruitblik:

d.w.z. Is:

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

gelijk aan:

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

???

— Update twee:

Volgens @andomar en @alan moore – je kunt dubbele negatieve vooruitblik niet verwisselen voor positieve vooruitblik.


Antwoord 1, autoriteit 100%

Een negatieve vooruitblik zegt dat op deze positie de volgende regex niet kan overeenkomen.

Laten we een vereenvoudigd voorbeeld nemen:

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

Het laatste voorbeeld is een dubbele ontkenning: het staat een b toe gevolgd door c. De geneste negatieve vooruitblik wordt een positieve vooruitblik: de c moet aanwezig zijn.

In elk voorbeeld komt alleen de a overeen. De vooruitblik is slechts een voorwaarde en wordt niet toegevoegd aan de overeenkomende tekst.


Antwoord 2, autoriteit 10%

Lookarounds kunnen worden genest.

Dus deze regex komt overeen met “drupal-6.14/” dat is niet gevolgd door “sites” dat is niet gevolgd door “/all” of “/default”.

Verwarrend? Met andere woorden kunnen we zeggen dat het overeenkomt met “drupal-6.14/” dat niet wordt gevolgd door “sites” tenzij dat verder wordt gevolgd door “/all” of “/ standaard”


Antwoord 3, autoriteit 4%

Als u uw reguliere expressie als volgt wijzigt:

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

…dan komt het overeen met alle invoer die drupal-6.14/ bevat, gevolgd door sites gevolgd door iets anders dan /all of /default. Bijvoorbeeld:

drupal-6.14/sites/foo
drupal-6.14/sites/bar
drupal-6.14/sitesfoo42
drupal-6.14/sitesall

Als u ?= wijzigt in ?! zodat deze overeenkomt met uw oorspronkelijke regex, worden deze overeenkomsten eenvoudigweg teniet gedaan:

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

Dit betekent dus gewoon dat drupal-6.14/ nu niet kan worden gevolgd door sites gevolgd door iets anders dan /all of /default. Dus nu zullen deze ingangen voldoen aan de regex:

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

Maar wat misschien niet duidelijk is uit sommige van de andere antwoorden (en mogelijk uw vraag) is dat uw regex ook andere invoer toestaat waarbij drupal-6.14/ wordt ook gevolgd door iets anders dan sites. Bijvoorbeeld:

drupal-6.14/foo
drupal-6.14/xsites

Conclusie: Dus, je regex zegt in feite dat je alle submappen van drupal-6.14 behalve die submappen moet opnemen van sites waarvan de naam begint met iets anders dan all of default.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

eight − six =

Other episodes