Hoe een specifiek woord in regex te negeren?

Ik weet dat ik een groep tekens kan negeren zoals in [^bar], maar ik heb een reguliere expressie nodig waarbij ontkenning van toepassing is op het specifieke woord – dus hoe kan ik in mijn voorbeeld een daadwerkelijke bar, en niet “elke tekens in bar”?


Antwoord 1, autoriteit 100%

Een goede manier om dit te doen is door negatieve vooruitblikte gebruiken:

^(?!.*bar).*$

De negatieve lookahead-constructie is het paar haakjes, met het haakje openen gevolgd door een vraagteken en een uitroepteken. Binnen de vooruitblik [is een regex-patroon].


Antwoord 2, autoriteit 8%

Tenzij prestaties van het grootste belang zijn, is het vaak gemakkelijker om uw resultaten een tweede keer te doorlopen en de resultaten over te slaan die overeenkomen met de woorden die u wilt negeren.

Reguliere uitdrukkingen betekenen meestal dat u toch bezig bent met scripten of een of andere taak met lage prestaties, dus zoek een oplossing die gemakkelijk te lezen, te begrijpen en te onderhouden is.


Antwoord 3, autoriteit 6%

U kunt ofwel een negatieve vooruitblik of achterom kijken:

^(?!.*?bar).*
^(.(?<!bar))*?$

Of gebruik alleen de basis:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$

Deze komen allemaal overeen met alles dat geen barbevat.


Antwoord 4, autoriteit 5%

Oplossing:

^(?!.*STRING1|.*STRING2|.*STRING3).*$

xxxxxx OK

xxxSTRING1xxx KO (is of het gewenst is)

xxxSTRING2xxx KO (is of het gewenst is)

xxxSTRING3xxx KO (is of het gewenst is)


Antwoord 5, autoriteit 5%

De volgende regex zal doen wat je wilt (zolang negatieve lookbehinds en lookaheads worden ondersteund), dingen goed matchen; het enige probleem is dat het overeenkomt met individuele tekens (dwz elke overeenkomst is een enkel teken in plaats van alle tekens tussen twee opeenvolgende “balken”), wat mogelijk resulteert in een potentieel hoge overhead als u met zeer lange tekenreeksen werkt.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]

Antwoord 6, autoriteit 4%

Ik kwam deze forumthread tegen toen ik probeerde een regex te identificeren voor de volgende Engelse verklaring:

Gegeven een invoerreeks, match allestenzijdeze invoerreeks exact ‘bar’ is; ik wil bijvoorbeeld zowel ‘barrier’ en ‘disbar’ als ‘foo’ matchen.

Hier is de regex die ik bedacht heb

^(bar.+|(?!bar).*)$

Mijn Engelse vertaling van de regex is “pas de tekenreeks aan als deze begint met ‘bar’ en deze heeft ten minste één ander teken, of als de tekenreeks niet begint met ‘bar’.


Antwoord 7, autoriteit 2%

Het geaccepteerde antwoord is leuk, maar het is echt een tijdelijke oplossing voor het ontbreken van een eenvoudige operator voor sub-expressie-ontkenning in regexes. Dit is de reden waarom grep --invert-matchwordt afgesloten. Dus in *nixes kun je het gewenste resultaat bereiken met behulp van pipes en een tweede regex.

grep 'something I want' | grep --invert-match 'but not these ones'

Nog steeds een tijdelijke oplossing, maar misschien makkelijker te onthouden.


Antwoord 8

Ik wil het geaccepteerde antwoord aanvullen en bijdragen aan de discussie met mijn late antwoord.

@ChrisVanOpstal heeft deze regex-tutorialgedeeld, wat een geweldige bron is om regex te leren.

Het kostte echter veel tijd om door te lezen.

Ik heb een spiekbriefje gemaakt voor het geheugensteuntje.

Deze referentie is gebaseerd op de accolades [], ()en {}die elke klas leiden, en ik vind het gemakkelijk om herinneren.

Regex = {
 'single_character': ['[]', '.', {'negate':'^'}],
 'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
 'repetition'      : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
 'anchor'          : ['^', '\b', '$'],
 'non_printable'   : ['\n', '\t', '\r', '\f', '\v'],
 'shorthand'       : ['\d', '\w', '\s'],
 }

Antwoord 9

Geëxtraheerd uit deze opmerkingdoor bkDJ:

^(?!bar$).*

De mooie eigenschap van deze oplossing is dat het mogelijk is om meerdere woorden duidelijk te negeren (uit te sluiten):

^(?!bar$|foo$|banana$).*

Antwoord 10

Ik heb net iets anders bedacht dat gedaan zou kunnen worden. Het is heel anders dan mijn eerste antwoord, omdat het geen reguliere expressies gebruikt, dus heb ik besloten om een tweede antwoord te posten.

Gebruik de split()-methode van uw taal die equivalent is aan de tekenreeks met het woord om te ontkennen als argument voor waarop u moet splitsen. Een voorbeeld met Python:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']

Het leuke van het op deze manier te doen, in ieder geval in Python (ik weet niet meer of de functionaliteit hetzelfde zou zijn in bijvoorbeeld Visual Basic of Java), is dat het je indirect laat weten wanneer “bar” werd herhaald in de string vanwege het feit dat de lege strings tussen “bar”s zijn opgenomen in de lijst met resultaten (hoewel de lege string aan het begin te wijten is aan het feit dat er een “bar” aan het begin van de string staat). Als je dat niet wilt, kun je gewoon de lege strings uit de lijst verwijderen.


Antwoord 11

Als het echt een woord, baris dat je niet wilt matchen, dan:

^(?!.*\bbar\b).*$

Het bovenstaande komt overeen met elke tekenreeks die geen barbevat die zich op een woordgrens bevindt, dat wil zeggen gescheiden van niet-woordtekens. De punt/punt (.) die in het bovenstaande patroon wordt gebruikt, komt echter niet overeen met nieuwe regeltekens, tenzij de juiste regex-vlag wordt gebruikt:

^(?s)(?!.*\bbar\b).*$

Alternatief:

^(?!.*\bbar\b)[\s\S]*$

In plaats van een speciale vlag te gebruiken, zoeken we naar elk teken dat witruimte of niet-witruimte is. Dat zou elk personage moeten omvatten.

Maar wat als we woorden willen matchen die misschien barbevatten, maar niet het specifieke woord bar?

(?!\bbar\b)\b\[A-Za-z-]*bar[a-z-]*\b
  1. (?!\bbar\b)Beweer dat de volgende invoer geen barop een woordgrens is.
  2. \b\[A-Za-z-]*bar[a-z-]*\bKomt overeen met elk woord op een woordgrens die barbevat.

Bekijk Regex-demo


Antwoord 12

Ik had een lijst met bestandsnamen en ik wilde bepaalde namen uitsluiten, met dit soort gedrag (Ruby):

files = [
  'mydir/states.rb',      # don't match these
  'countries.rb',
  'mydir/states_bkp.rb',  # match these
  'mydir/city_states.rb' 
]
excluded = ['states', 'countries']
# set my_rgx here
result = WankyAPI.filter(files, my_rgx)  # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']

Hier is mijn oplossing:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|')
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/

Mijn veronderstellingen voor deze toepassing:

  • De tekenreeks die moet worden uitgesloten, staat aan het begin van de invoer of direct na een schuine streep.
  • De toegestane strings eindigen op .rb.
  • Toegestane bestandsnamen hebben geen teken .vóór de .rb.

Other episodes