Vraag Reguliere expressie om overeen te komen met een regel die geen woord bevat?


Ik weet dat het mogelijk is een woord te matchen en vervolgens de overeenkomsten om te keren met andere hulpmiddelen (bijv. grep -v). Ik zou echter graag willen weten of het mogelijk is om dat te evenaren niet doen een specifiek woord bevatten (bijvoorbeeld hede) met behulp van een reguliere expressie.

Invoer:

hoho
hihi
haha
hede

Code:

grep "<Regex for 'doesn't contain hede'>" input

Gewenste output:

hoho
hihi
haha

3559


oorsprong


antwoorden:


Het idee dat regex inverse matching niet ondersteunt, is niet helemaal waar. Je kunt dit gedrag nabootsen door negatieve rondkijken te gebruiken:

^((?!hede).)*$

De bovenstaande regex komt overeen met elke tekenreeks, of regel zonder regelreeks, niet met de (sub) string 'hede'. Zoals gezegd, dit is niet iets dat regex 'goed' is (of moet doen), maar toch is mogelijk.

En als u ook line break chars moet matchen, gebruik dan de DOT-ALL-modifier (de achterstand s in het volgende patroon):

/^((?!hede).)*$/s

of gebruik het inline:

/(?s)^((?!hede).)*$/

(waar de /.../ zijn de regex-scheidingstekens, d.w.z. geen deel van het patroon)

Als de DOT-ALL-modifier niet beschikbaar is, kunt u hetzelfde gedrag nabootsen met de tekenklasse [\s\S]:

/^((?!hede)[\s\S])*$/

Uitleg

Een string is slechts een lijst van n karakters. Voor en na elk personage is er een lege tekenreeks. Dus een lijst van n karakters zullen hebben n+1 lege reeksen. Overweeg de string "ABhedeCD":

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
S = │e1│ A │e2│ B │e3│ h │e4│ e │e5│ d │e6│ e │e7│ C │e8│ D │e9│
    └──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┴───┴──┘

index    0      1      2      3      4      5      6      7

waar de ezijn de lege reeksen. De regex (?!hede). kijkt vooruit om te zien of er geen substring is "hede" om gezien te worden, en als dat het geval is (dus iets anders wordt gezien), dan is het . (punt) komt overeen met elk teken behalve een regeleinde. Look-arounds worden ook wel genoemd zero-breedte beweringen omdat ze dat niet doen consumeren alle karakters. Ze beweren / valideren alleen iets.

Dus in mijn voorbeeld wordt elke lege string eerst gevalideerd om te zien of er geen is "hede" verderop, voordat een personage wordt geconsumeerd door de . (punt). De regex (?!hede). zal dat slechts één keer doen, dus het is verpakt in een groep en wordt nul of meer keer herhaald: ((?!hede).)*. Ten slotte zijn de start- en eindinvoer verankerd om ervoor te zorgen dat de volledige invoer wordt verbruikt: ^((?!hede).)*$

Zoals je kunt zien, de invoer "ABhedeCD" zal mislukken omdat op e3, de regex (?!hede) faalt (daar is  "hede" vooruit!).


4852



Merk op dat de oplossing voor doet niet beginnen met “Hede”:

^(?!hede).*$

is over het algemeen veel efficiënter dan de oplossing voor doet niet bevatten “Hede”:

^((?!hede).)*$

De eerste controleert "hede" alleen op de eerste positie van de invoerreeks, in plaats van op elke positie.


603



Als je gebruikt het gewoon voor grep, je kunt gebruiken grep -v hede om alle regels te krijgen die geen hede bevatten.

ETA Oh, de vraag herlezen, grep -v is waarschijnlijk wat je bedoelde met "gereedschapsopties".


163



Antwoord:

^((?!hede).)*$

Uitleg:

^het begin van de string, ( groeperen en vastleggen op \ 1 (0 of meer keer (overeenkomend met het meest mogelijke bedrag)),
(?! kijk vooruit om te zien of er geen is,

hedejouw touwtje,

) einde van de look-ahead, . elk teken behalve \ n,
)* einde van \ 1 (Opmerking: omdat u een kwantor gebruikt bij deze opname, wordt alleen de LAATSTE herhaling van het vastgelegde patroon opgeslagen in \ 1)
$ vóór een optionele \ n, en het einde van de string


121



De gegeven antwoorden zijn prima, alleen een academisch punt:

Reguliere expressies in de betekenis van theoretische computerwetenschappen NIET KAN ZIJN doe het zo. Voor hen moest het er ongeveer zo uitzien:

^([^h].*$)|(h([^e].*$|$))|(he([^h].*$|$))|(heh([^e].*$|$))|(hehe.+$) 

Dit doet alleen een VOLLEDIGE match. Doen voor sub-wedstrijden zou zelfs meer lastig zijn.


89



Als u de regex-test wilt enkel en alleen falen als het hele reeks wedstrijden, het volgende werkt:

^(?!hede$).*

bijv. - Als u wilt toestaan ​​dat alle waarden behalve "foo" (d.w.z. "foofoo", "barfoo" en "foobar" zullen passeren, maar "foo" zullen mislukken), gebruik dan: ^(?!foo$).*

Natuurlijk, als u zoekt naar exact gelijkheid, een betere algemene oplossing in dit geval is om te controleren op stringgelijkheid, d.w.z.

myStr !== 'foo'

Je zou zelfs de ontkenning kunnen plaatsen buiten de test als je regex-functies nodig hebt (hier, hoofdletterongevoeligheid en bereikafstemming):

!/^[a-f]oo$/i.test(myStr)

De regex-oplossing aan de bovenkant kan echter nuttig zijn in situaties waarin een positieve regex-test vereist is (misschien door een API).


48



hier is een goede uitleg van waarom het niet gemakkelijk is om een ​​willekeurige regex te ontkennen. Ik ben het echter met de andere antwoorden eens: als dit iets anders is dan een hypothetische vraag, dan is een regex hier niet de juiste keuze.


47