Reguliere expressies: is er een AND-operator?

Uiteraard kunt u de |(pipe?) gebruiken om ORvoor te stellen, maar is er ook een manier om ANDweer te geven?

In het bijzonder wil ik alinea’s met tekst matchen die ALLES van een bepaalde zin bevatten, maar in willekeurige volgorde.


Antwoord 1, autoriteit 100%

Gebruik een niet-verslindende reguliere expressie.

De typische (bijv. Perl/Java) notatie is:

(?=expr)

Dit betekent “match exprmaar ga daarna verder met matchen op het oorspronkelijke matchpunt.”

Je kunt er zoveel doen als je wilt, en dit zal een ‘en’ zijn. Voorbeeld:

(?=match this expression)(?=match this too)(?=oh, and this)

Je kunt zelfs capture-groepen toevoegen aan de niet-consumerende uitdrukkingen als je een deel van de gegevens daarin wilt opslaan.


Antwoord 2, autoriteit 90%

Je moet vooruitkijken gebruiken, zoals sommige andere respondenten hebben gezegd, maar de vooruitblik moet rekening houden met andere tekens tussen het doelwoord en de huidige overeenkomstpositie. Bijvoorbeeld:

(?=.*word1)(?=.*word2)(?=.*word3)

De .*in de eerste vooruitblik laat het overeenkomen met het aantal tekens dat nodig is voordat het bij “woord1” komt. Vervolgens wordt de wedstrijdpositie gereset en zoekt de tweede vooruitblik naar “woord2”. Reset opnieuw, en het laatste deel komt overeen met “word3”; aangezien dit het laatste woord is waar je naar zoekt, is het niet nodig dat het vooruitkijkt, maar het kan geen kwaad.

Om een hele alinea te matchen, moet je de regex aan beide uiteinden verankeren en een laatste .*toevoegen om de resterende tekens te gebruiken. Met behulp van Perl-stijl notatie zou dat zijn:

/^(?=.*word1)(?=.*word2)(?=.*word3).*$/m

De ‘m’-modifier is voor multiline-modus; het laat de ^en $overeenkomen bij alineagrenzen (“regelgrenzen” in regex-spreken). Het is in dit geval van essentieel belang dat u geende modifier ‘s’ gebruikt, waarmee het metateken van de punt overeenkomt met zowel nieuwe regels als alle andere tekens.

Ten slotte wil je er zeker van zijn dat je hele woorden matcht en niet alleen fragmenten van langere woorden, dus je moet woordgrenzen toevoegen:

/^(?=.*\bword1\b)(?=.*\bword2\b)(?=.*\bword3\b).*$/m

Antwoord 3, autoriteit 11%

Bekijk dit voorbeeld:

We hebben 2 regexps A en B en we willen ze allebei matchen, dus in pseudo-code ziet het er als volgt uit:

pattern = "/A AND B/"

Het kan als volgt worden geschreven zonder de operator AND te gebruiken:

pattern = "/NOT (NOT A OR NOT B)/"

in PCRE:

"/(^(^A|^B))/"
regexp_match(pattern,data)

Antwoord 4, autoriteit 8%

De AND-operator is implicietin de RegExp-syntaxis.
De OR-operator moet in plaats daarvan worden gespecificeerd met een pijp.
De volgende RegExp:

var re = /ab/;

betekent de letter aENde letter b.
Het werkt ook met groepen:

var re = /(co)(de)/;

het betekent de groep coENde groep de.
Het vervangen van de (impliciete) EN door een OF zou de volgende regels vereisen:

var re = /a|b/;
var re = /(co)|(de)/;

Antwoord 5, autoriteit 7%

Je kunt dat doen met een reguliere expressie, maar waarschijnlijk wil je iets anders. Gebruik bijvoorbeeld meerdere regexp en combineer ze in een if-clausule.

Je kunt alle mogelijke permutaties opsommen met een standaard regexp, zoals deze (komt overeen met a, b en c in willekeurige volgorde):

(abc)|(bca)|(acb)|(bac)|(cab)|(cba)

Dit maakt echter een erg lange en waarschijnlijk inefficiënte regexp, als je meer dan een paar termen hebt.

Als je een of andere uitgebreide regexp-versie gebruikt, zoals die van Perl of Java, hebben ze betere manieren om dit te doen. Andere antwoorden hebben gesuggereerd om een positieve vooruitblik te gebruiken.


Antwoord 6, autoriteit 3%

Is het in jouw geval niet mogelijk om de AND te doen op meerdere overeenkomende resultaten? in pseudocode

regexp_match(pattern1, data) && regexp_match(pattern2, data) && ...

Antwoord 7, autoriteit 3%

Waarom gebruik je awk niet?
met awk regex AND, OR is zo eenvoudig

awk '/WORD1/ && /WORD2/ && /WORD3/' myfile

Antwoord 8, autoriteit 2%

Als u Perl-reguliere expressies gebruikt, kunt u een positieve kijk vooruit gebruiken:

Bijvoorbeeld

(?=[1-9][0-9]{2})[0-9]*[05]\b

zou getallen groter dan 100 zijn en deelbaar door 5


Antwoord 9, Autoriteit 2%

Naast het geaccepteerde antwoord

Ik zal u een aantal praktische voorbeelden geven die dingen duidelijker zullen krijgen voor sommigen van u. Laat bijvoorbeeld zeggen dat we die drie lijnen van tekst hebben:

[12/Oct/2015:00:37:29 +0200] // only this + will get selected
[12/Oct/2015:00:37:x9 +0200]
[12/Oct/2015:00:37:29 +020x]

Zie demo hier Demo

Wat we hier willen doen is om het + -teken te selecteren, maar alleen als het na twee nummers met een ruimte is en als het vóór vier nummers is. Dat zijn de enige beperkingen. We zouden deze reguliere expressie gebruiken om het te bereiken:

'~(?<=\d{2} )\+(?=\d{4})~g'

Opmerking Als u de uitdrukking scheidt, geeft het u verschillende resultaten.

of misschien wil je wat tekst selecteren tussen tags … maar niet de tags! Dan zou u kunnen gebruiken:

'~(?<=<p>).*?(?=<\/p>)~g'

Voor deze tekst:

<p>Hello !</p> <p>I wont select tags! Only text with in</p> 

Zie demo hier Demo


Antwoord 10, Autoriteit 2%

U kunt uw uitvoer naar een andere regex pijpen. Gref gebruiken, kunt u dit doen:

grep A | grep B


Antwoord 11, Autoriteit 2%

De volgorde is altijd geïmpliceerd in de structuur van de reguliere expressie. Om te bereiken wat je wilt, moet je de invoerreeks meerdere keren vergelijken met verschillende uitdrukkingen.

Wat je wilt doen is nietmogelijk met een enkele regexp.


Antwoord 12

Gebruik AND buiten de reguliere expressie. In PHP leek de lookahead-operator niet voor mij te werken, in plaats daarvan gebruikte ik dit

if( preg_match("/^.{3,}$/",$pass1) && !preg_match("/\s{1}/",$pass1))
    return true;
else
    return false;

De bovenstaande regex komt overeen als de lengte van het wachtwoord 3 tekens of meer is en er geen spaties in het wachtwoord staan.


Antwoord 13

((yes).*(no))|((no).*(yes))

Komt overeen met een zin die zowel yesals nobevat, ongeacht de volgorde waarin ze verschijnen:

Do i like cookies? **Yes**, i do. But milk - **no**, definitely no.

**No**, you may not have my phone. **Yes**, you may go f yourself.

Zullen beide overeenkomen, hoofdletters negeren.


Antwoord 14

Hier is een mogelijk “formulier” voor de “en”-operator:

Neem de volgende regex als voorbeeld:

Als we woorden willen matchen zonder het “e”-teken, kunnen we dit doen:

/\b[^\We]+\b/g
  • \Wbetekent GEEN “woord”-teken.
  • ^\Wbetekent een “woord”-teken.
  • [^\We]betekent een “woord”-teken, maar geen “e”.

zie het in actie: woord zonder e

‘en’-operator voor reguliere expressies

Ik denk dat dit patroon kan worden gebruikt als een “en“-operator voor reguliere expressies.

In het algemeen, als:

  • A = not a
  • B = not b

dan:

[^AB] = not(A or B) 
      = not(A) and not(B) 
      = a and b

Verschillenset

Dus, als we het concept van verschillensetwillen implementeren in reguliere expressies, zou dit kunnen doen:

a - b = a and not(b)
      = a and B
      = [^Ab]

Other episodes