Reguliere uitdrukking die overeenkomt met een regel die geen woord bevat

Ik weet dat het mogelijk is om een ​​woord te matchen en de matches vervolgens om te draaien met andere tools (bijv. grep -v). Is het echter mogelijk om regels te matchen die geen specifiek woord bevatten, b.v. hede, gebruik je een reguliere expressie?

Invoer:

hoho
hihi
haha
hede

Code:

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

Gewenste output:

hoho
hihi
haha

Antwoord 1, autoriteit 100%

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

^((?!hede).)*$

De regex hierboven komt overeen met elke tekenreeks of regel zonder regeleinde, niet die de (sub)tekenreeks ‘hede’ bevat. Zoals gezegd, dit is niet iets waar regex “goed” in is (of zou moeten doen), maar toch is het is mogelijk.

En als je ook regeleinde-tekens moet matchen, gebruik dan de DOT-ALL-modifier (de achterliggende s in het volgende patroon):

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

of gebruik het inline:

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

(waar de /.../ de regex-scheidingstekens zijn, d.w.z. geen deel uitmaken 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 tekenreeks is slechts een lijst van n-tekens. Voor en na elk teken is er een lege string. Een lijst met n-tekens heeft dus n+1 lege tekenreeksen. Beschouw de string "ABhedeCD":

    ---T---T--T---T--T---T--T---T--T---T--T---T--T---T--T---T--¬
S = ¦e1¦ A ¦e2¦ B ¦e3¦ h ¦e4¦ e ¦e5¦ d ¦e6¦ e ¦e7¦ C ¦e8¦ D ¦e9¦
    L--+---+--+---+--+---+--+---+--+---+--+---+--+---+--+---+---
index    0      1      2      3      4      5      6      7

waarbij de e‘s de lege strings zijn. De regex (?!hede). kijkt vooruit om te zien of er geen substring "hede" te zien is, en of dat het geval is (er wordt dus iets anders gezien) , dan komt de . (punt) overeen met elk teken behalve een regeleinde. Look-arounds worden ook zero-width-assertions genoemd omdat ze geen tekens verbruiken. Ze bevestigen/bevestigen alleen iets.

Dus in mijn voorbeeld wordt elke lege tekenreeks eerst gevalideerd om te zien of er geen "hede" verderop staat, voordat een teken wordt gebruikt door de . (punt ). De regex (?!hede). doet dat maar één keer, dus het is verpakt in een groep en nul of meer keer herhaald: ((?!hede).)*. Ten slotte zijn het begin en het einde van de invoer verankerd om ervoor te zorgen dat de volledige invoer wordt verbruikt: ^((?!hede).)*$

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


Antwoord 2, autoriteit 12%

Merk op dat de oplossing voor niet begint met hede :

^(?!hede).*$

is over het algemeen veel efficiënter dan de oplossing voor bevat niet hede :

^((?!hede).)*$

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


Antwoord 3, autoriteit 3%

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

ETA Oh, als ik de vraag herlees, grep -v is waarschijnlijk wat je bedoelde met “tools options”.


Antwoord 4, autoriteit 3%

Antwoord:

^((?!hede).)*$

Uitleg:

^het begin van de tekenreeks,
( groeperen en vastleggen tot \1 (0 of meer keren (komt overeen met het hoogst mogelijke aantal)),
(?! kijk vooruit om te zien of er geen is,

hede je string,

) einde vooruitblik,
. elk teken behalve \n,
)* einde van \1 (Opmerking: omdat u bij deze opname een kwantor gebruikt, wordt alleen de LAATSTE herhaling van het vastgelegde patroon opgeslagen in \1)
$ voor een optionele \n en het einde van de tekenreeks


Antwoord 5, autoriteit 2%

De gegeven antwoorden zijn prima, alleen een academisch punt:

Reguliere uitdrukkingen in de betekenis van theoretische computerwetenschappen KUNNEN NIET doen het zo. Voor hen moest het er ongeveer zo uitzien:

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

Dit levert alleen een VOLLEDIGE overeenkomst op. Het zou zelfs nog lastiger zijn om het voor subwedstrijden te doen.


Antwoord 6

Als u wilt dat de regex-test alleen mislukt als de hele tekenreeks overeenkomt, werkt het volgende:

^(?!hede$).*

bijv. — Als u alle waarden behalve “foo” wilt toestaan ​​(dwz “foofoo”, “barfoo” en “foobar” zullen slagen, maar “foo” zal niet werken), gebruik dan: ^(?!foo$).*

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

myStr !== 'foo'

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

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

De regex-oplossing bovenaan dit antwoord kan echter nuttig zijn in situaties waarin een positieve regex-test vereist is (misschien door een API).


Antwoord 7

FWIW, aangezien reguliere talen (ook wel rationele talen) gesloten zijn onder complementatie, is het altijd mogelijk om een ​​reguliere expressie (ook wel rationele expressie genoemd) te vinden die een andere expressie negeert. Maar niet veel tools implementeren dit.

Vcsn ondersteunt deze operator (die wordt aangeduid met {c}, postfix).

U definieert eerst het type van uw uitdrukkingen: labels zijn letters (lal_char) om te kiezen uit a tot z bijvoorbeeld (definiëren van de alfabet bij het werken met complementatie is natuurlijk erg belangrijk), en de “waarde” die voor elk woord wordt berekend, is slechts een Boolean: true het woord wordt geaccepteerd, false, afgewezen.

In Python:

In [5]: import vcsn
        c = vcsn.context('lal_char(a-z), b')
        c
Out[5]: {a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z} > ??

vervolgens voer je je uitdrukking in:

In [6]: e = c.expression('(hede){c}'); e
Out[6]: (hede)^c

converteer deze uitdrukking naar een automaat:

In [7]: a = e.automaton(); a

De bijbehorende automaat

tot slot, converteer deze automaat terug naar een eenvoudige uitdrukking.

In [8]: print(a.expression())
        \e+h(\e+e(\e+d))+([^h]+h([^e]+e([^d]+d([^e]+e[^]))))[^]*

waar + meestal wordt aangeduid met |, \e staat voor het lege woord en [^] is meestal geschreven . (elk teken). Dus, met een beetje herschrijven van ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*.

U kunt dit voorbeeld hier bekijken, en probeer Vcsn online daar.


Antwoord 8

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


Antwoord 9

Met negatieve vooruitzichten kan reguliere expressie overeenkomen met iets dat geen specifiek patroon bevat. Dit wordt beantwoord en toegelicht door Bart Kiers. Geweldige uitleg!

Met het antwoord van Bart Kiers zal het vooruitziende gedeelte echter 1 tot 4 karakters vooruit testen terwijl het overeenkomt met een enkel karakter. We kunnen dit vermijden en het vooruitziende gedeelte de hele tekst laten bekijken, ervoor zorgen dat er geen ‘hede’ is, en dan kan het normale gedeelte (.*) de hele tekst in één keer opeten.

Hier is de verbeterde regex:

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

Merk op dat de (*?) luie kwantor in het negatieve vooruitkijkgedeelte optioneel is, je kunt in plaats daarvan (*) hebzuchtige kwantor gebruiken, afhankelijk van je gegevens: als ‘hede’ aanwezig is en in de eerste helft van de tekst, wordt de luie kwantor kan sneller zijn; anders is de hebzuchtige kwantor sneller. Als ‘hede’ echter niet aanwezig is, zouden beide even traag zijn.

Hier is de democode.

Voor meer informatie over lookahead, bekijk het geweldige artikel: Mastering Lookahead en Lookbehind.

Bekijk ook eens RegexGen.js, een JavaScript-generator voor reguliere expressies die helpt bij het bouwen van complexe reguliere expressies. Met RegexGen.js kunt u de regex op een meer leesbare manier construeren:

var _ = regexGen;
var regex = _(
    _.startOfLine(),             
    _.anything().notContains(       // match anything that not contains:
        _.anything().lazy(), 'hede' //   zero or more chars that followed by 'hede',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);

Antwoord 10

Benchmarks

Ik heb besloten om enkele van de gepresenteerde opties te evalueren en hun prestaties te vergelijken, en om ook enkele nieuwe functies te gebruiken.
Benchmarking op .NET Regex Engine: http://regexhero.net/tester/

Benchmarktekst:

De eerste 7 regels mogen niet overeenkomen, omdat ze de gezochte uitdrukking bevatten, terwijl de onderste 7 regels moeten overeenkomen!

Regex Hero is a real-time online Silverlight Regular Expression Tester.
XRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex HeroRegex HeroRegex HeroRegex HeroRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her Regex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.Regex Hero
egex Hero egex Hero egex Hero egex Hero egex Hero egex Hero Regex Hero is a real-time online Silverlight Regular Expression Tester.
RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRegex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her
egex Hero
egex Hero is a real-time online Silverlight Regular Expression Tester.
Regex Her is a real-time online Silverlight Regular Expression Tester.
Regex Her Regex Her Regex Her Regex Her Regex Her Regex Her is a real-time online Silverlight Regular Expression Tester.
Nobody is a real-time online Silverlight Regular Expression Tester.
Regex Her o egex Hero Regex  Hero Reg ex Hero is a real-time online Silverlight Regular Expression Tester.

Resultaten:

Resultaten zijn iteraties per seconde als de mediaan van 3 runs – Groter getal = beter

01: ^((?!Regex Hero).)*$                    3.914   // Accepted Answer
02: ^(?:(?!Regex Hero).)*$                  5.034   // With Non-Capturing group
03: ^(?>[^R]+|R(?!egex Hero))*$             6.137   // Lookahead only on the right first letter
04: ^(?>(?:.*?Regex Hero)?)^.*$             7.426   // Match the word and check if you're still at linestart
05: ^(?(?=.*?Regex Hero)(?#fail)|.*)$       7.371   // Logic Branch: Find Regex Hero? match nothing, else anything
P1: ^(?(?=.*?Regex Hero)(*FAIL)|(*ACCEPT))  ?????   // Logic Branch in Perl - Quick FAIL
P2: .*?Regex Hero(*COMMIT)(*FAIL)|(*ACCEPT) ?????   // Direct COMMIT & FAIL in Perl

Omdat .NET geen actiewerkwoorden (*FAIL, etc.) ondersteunt, kon ik de oplossingen P1 en P2 niet testen.

Samenvatting:

Ik heb geprobeerd de meeste voorgestelde oplossingen te testen, sommige optimalisaties zijn mogelijk voor bepaalde woorden.
Als de eerste twee letters van de zoekreeks bijvoorbeeld niet hetzelfde zijn, kan antwoord 03 worden uitgebreid tot:
^(?>[^R]+|R+(?!egex Hero))*$ wat resulteert in een kleine prestatiewinst.

Maar de over het algemeen meest leesbare en qua prestaties snelste oplossing lijkt 05 te zijn met een voorwaardelijke instructie
of 04 met de bezittelijke kwantor. Ik denk dat de Perl-oplossingen nog sneller en beter leesbaar moeten zijn.


Antwoord 11

Geen regex, maar ik vond het logisch en handig om seriële greps met pijp te gebruiken om ruis te elimineren.

bijv. zoek een apache-configuratiebestand zonder alle opmerkingen-

grep -v '\#' /opt/lampp/etc/httpd.conf      # this gives all the non-comment lines

en

grep -v '\#' /opt/lampp/etc/httpd.conf |  grep -i dir

De logica van seriële grep’s is (geen commentaar) en (komt overeen met dir)


Antwoord 12

Hiermee vermijdt u een vooruitblik op elke positie te testen:

/^(?:[^h]+|h++(?!ede))*+$/

gelijk aan (voor .net):

^(?>(?:[^h]+|h+(?!ede))*)$

Oud antwoord:

/^(?>[^h]+|h+(?!ede))*$/

Antwoord 13

Voornoemde (?:(?!hede).)* is geweldig omdat het verankerd kan worden.

^(?:(?!hede).)*$               # A line without hede
foo(?:(?!hede).)*bar           # foo followed by bar, without hede between them

Maar in dit geval zou het volgende voldoende zijn:

^(?!.*hede)                    # A line without hede

Deze vereenvoudiging is klaar om “AND”-clausules toe te voegen:

^(?!.*hede)(?=.*foo)(?=.*bar)   # A line with foo and bar, but without hede
^(?!.*hede)(?=.*foo).*bar       # Same

Antwoord 14

Zo zou ik het doen:

^[^h]*(h(?!ede)[^h]*)*$

Nauwkeuriger en efficiënter dan de andere antwoorden. Het implementeert Friedl’s “unrolling-the-loop” efficiëntietechniek en vereist veel minder backtracking.


Antwoord 15

Een, naar mijn mening, beter leesbare variant van het bovenste antwoord:

^(?!.*hede)

Kortom, “kom overeen met het begin van de regel als en alleen als er geen ‘hede’ in staat” – dus de vereiste is vrijwel direct vertaald naar regex.

Natuurlijk is het mogelijk om meerdere faalvereisten te hebben:

^(?!.*(hede|hodo|hada))

Details: het ^-anker zorgt ervoor dat de regex-engine de overeenkomst niet opnieuw probeert op elke locatie in de tekenreeks, die bij elke tekenreeks zou passen.

Het ^-anker in het begin is bedoeld om het begin van de regel weer te geven. De grep-tool past elke regel één voor één aan, in contexten waar u met een reeks met meerdere regels werkt, kunt u de vlag “m” gebruiken:

/^(?!.*hede)/m # JavaScript syntax

of

(?m)^(?!.*hede) # Inline flag

Antwoord 16

Als je een teken wilt matchen om een ​​woord te negeren dat lijkt op negate character class:

Bijvoorbeeld een tekenreeks:

<?
$str="aaa        bbb4      aaa     bbb7";
?>

Niet gebruiken:

<?
preg_match('/aaa[^bbb]+?bbb7/s', $str, $matches);
?>

Gebruik:

<?
preg_match('/aaa(?:(?!bbb).)+?bbb7/s', $str, $matches);
?>

Let op "(?!bbb)." is geen blik achter of vooruit, het is actueel, bijvoorbeeld:

"(?=abc)abcde", "(?!abc)abcde"

Antwoord 17

Omdat niemand anders een direct antwoord heeft gegeven op de vraag die werd gesteld, doe ik het.

Het antwoord is dat het met POSIX grep onmogelijk is om letterlijk aan dit verzoek te voldoen:

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

De reden is dat POSIX grep alleen nodig is om te werken met Basis reguliere expressies, die gewoon niet krachtig genoeg zijn om die taak te volbrengen (ze zijn niet in staat om alle reguliere talen te ontleden vanwege een gebrek aan afwisseling).

Echter implementeert GNU grep extensies die dit toestaan. In het bijzonder is \| de alternatie-operator in GNU’s implementatie van BRE’s. Als uw reguliere expressie-engine afwisseling, haakjes en de Kleene-ster ondersteunt en in staat is om aan het begin en einde van de tekenreeks te verankeren, is dat alles wat u nodig heeft voor deze benadering. Merk echter op dat negatieve sets [^ ... ] erg handig zijn als aanvulling op deze, omdat je ze anders moet vervangen door een uitdrukking van de vorm (a|b|c| ... ) die elk teken vermeldt dat niet in de set zit, wat extreem vervelend en te lang is, vooral als de hele tekenset Unicode is.

Dankzij de formele taaltheorie krijgen we te zien hoe zo’n uitdrukking eruitziet. Met GNU grep zou het antwoord zoiets zijn als:

grep "^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$" input

(gevonden met Graal en enkele verdere met de hand gemaakte optimalisaties).

Je kunt ook een tool gebruiken die Uitgebreide reguliere expressies, zoals egrep, om de backslashes te verwijderen:

egrep "^([^h]|h(h|eh|edh)*([^eh]|e[^dh]|ed[^eh]))*(|h(h|eh|edh)*(|e|ed))$" input

Hier is een script om het te testen (merk op dat het een bestand testinput.txt genereert in de huidige map). Verschillende van de gepresenteerde uitdrukkingen slagen niet voor deze test.

#!/bin/bash
REGEX="^\([^h]\|h\(h\|eh\|edh\)*\([^eh]\|e[^dh]\|ed[^eh]\)\)*\(\|h\(h\|eh\|edh\)*\(\|e\|ed\)\)$"
# First four lines as in OP's testcase.
cat > testinput.txt <<EOF
hoho
hihi
haha
hede
h
he
ah
head
ahead
ahed
aheda
ahede
hhede
hehede
hedhede
hehehehehehedehehe
hedecidedthat
EOF
diff -s -u <(grep -v hede testinput.txt) <(grep "$REGEX" testinput.txt)

In mijn systeem wordt afgedrukt:

Files /dev/fd/63 and /dev/fd/62 are identical

zoals verwacht.

Voor degenen die geïnteresseerd zijn in de details, de gebruikte techniek is om de reguliere expressie die overeenkomt met het woord om te zetten in een eindige automaat, vervolgens de automaat om te keren door elke acceptatiestatus te wijzigen in niet-acceptatie en vice versa, en vervolgens de resulterende FA terug naar een reguliere expressie.

Zoals iedereen heeft opgemerkt, is de reguliere expressie veel eenvoudiger als uw engine voor reguliere expressies negatieve lookahead ondersteunt. Bijvoorbeeld met GNU grep:

grep -P '^((?!hede).)*$' input

Deze benadering heeft echter het nadeel dat er een backtracking-engine voor reguliere expressies nodig is. Dit maakt het ongeschikt in installaties die gebruikmaken van beveiligde reguliere expressie-engines zoals RE2, wat een reden om in sommige omstandigheden de voorkeur te geven aan de gegenereerde aanpak.

Gebruikmakend van de uitstekende FormalTheory-bibliotheek van Kendall Hopkins, geschreven in PHP, die een functionaliteit biedt die vergelijkbaar is met Grail , en een vereenvoudiging die door mezelf is geschreven, heb ik een online generator van negatieve reguliere expressies kunnen schrijven met een invoerzin (alleen alfanumerieke en spatietekens worden momenteel ondersteund): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Voor hede voert het uit:

^([^h]|h(h|e(h|dh))*([^eh]|e([^dh]|d[^eh])))*(h(h|e(h|dh))*(ed?)?)?$

wat gelijk is aan het bovenstaande.


Antwoord 18

Het OP heeft het bericht niet gespecificeerd of Tag gegeven om de context (programmeertaal, editor, tool) aan te geven waarin de Regex zal worden gebruikt.

Voor mij moet ik dit soms doen tijdens het bewerken van een bestand met Textpad.

Textpad ondersteunt sommige Regex, maar biedt geen ondersteuning voor vooruitkijken of vooruitkijken, dus het duurt een paar stappen.

Als ik alle regels wil behouden die NIET de tekenreeks hede bevatten, zou ik dat doen het als volgt:

1. Zoek/vervang het hele bestand om een ​​unieke “Tag” toe te voegen aan het begin van elke regel die tekst bevat.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Verwijder alle regels die de string hede bevatten (vervangende string is leeg):

    Search string:<@#-unique-#@>.*hede.*\n  
    Replace string:<nothing>  
    Replace-all  

3. Op dit punt bevatten alle resterende regels NIET de tekenreeks hede. Verwijder de unieke “Tag” van alle regels (vervangende string is leeg):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

Nu heb je de originele tekst met alle regels die de tekenreeks hede bevatten, verwijderd.


Als ik iets anders wil doen om alleen regels te gebruiken die NIET de tekenreeks hede, ik zou het als volgt doen:

1. Zoek/vervang het hele bestand om een ​​unieke “Tag” toe te voegen aan het begin van elke regel die tekst bevat.

    Search string:^(.)  
    Replace string:<@#-unique-#@>\1  
    Replace-all  

2. Voor alle regels die de string hede bevatten, verwijder de unieke “Tag”:

    Search string:<@#-unique-#@>(.*hede)
    Replace string:\1  
    Replace-all  

3. Op dit punt bevatten alle regels die beginnen met de unieke “Tag”, NIET de tekenreeks hede. Ik kan nu mijn Iets Anders doen met alleen die regels.

4. Als ik klaar ben, verwijder ik de unieke “Tag” van alle regels (vervangende string is leeg):

    Search string:<@#-unique-#@>
    Replace string:<nothing>  
    Replace-all  

Antwoord 19

Een andere optie is om een ​​positieve vooruitblik toe te voegen en te controleren of hede ergens in de invoerregel staat, dan zouden we dat ontkennen, met een uitdrukking die lijkt op:

^(?!(?=.*\bhede\b)).*$

met woordgrenzen.


De uitdrukking wordt uitgelegd in het rechterbovenpaneel van regex101.com, als je dat wilt om het te verkennen/vereenvoudigen/aanpassen, en in deze link kun je zien hoe het zou match met enkele voorbeeldinvoer, als je wilt.


RegEx-circuit

jex.im visualiseert reguliere expressies:

voer hier de afbeeldingsbeschrijving in


Antwoord 20

Sinds de introductie van ruby-2.4.1 kunnen we de nieuwe Absent Operator in Ruby’s reguliere expressies

van de officiële doc

(?~abc) matches: "", "ab", "aab", "cccc", etc.
It doesn't match: "abc", "aabc", "ccccabc", etc.

Dus in jouw geval doet ^(?~hede)$ het werk voor jou

2.4.1 :016 > ["hoho", "hihi", "haha", "hede"].select{|s| /^(?~hede)$/.match(s)}
 => ["hoho", "hihi", "haha"]

Antwoord 21

Via PCRE werkwoord (*SKIP)(*F)

^hede$(*SKIP)(*F)|^.*$

Hierdoor wordt de regel die de exacte tekenreeks hede bevat volledig overgeslagen en komt alle overige regels overeen.

DEMO

Uitvoering van de onderdelen:

Laten we de bovenstaande regex eens bekijken door deze in twee delen te splitsen.

  1. Deel voor het |-symbool. Onderdeel mag niet overeenkomen.

    ^hede$(*SKIP)(*F)
    
  2. Gedeelte na het symbool |. Onderdeel moet overeenkomen.

    ^.*$
    

DEEL 1

De Regex-engine start de uitvoering vanaf het eerste deel.

^hede$(*SKIP)(*F)

Uitleg:

  • ^ Beweert dat we aan het begin staan.
  • hede Komt overeen met de tekenreeks hede
  • $ Beweert dat we aan het einde van de regel zijn.

Dus de regel die de tekenreeks hede bevat, zou overeenkomen. Zodra de regex-engine het volgende (*SKIP)(*F) ziet (Opmerking: u zou (*F) kunnen schrijven als (*FAIL)) werkwoord, het slaat over en zorgt ervoor dat de match mislukt. | genaamd wijziging of logische OR-operator toegevoegd naast het PCRE-werkwoord dat op zijn beurt overeenkomt met alle grenzen die bestaan ​​tussen elk en elk teken op alle regels, behalve dat de regel de exacte tekenreeks hede. Bekijk hier de demo. Dat wil zeggen, het probeert de tekens uit de resterende reeks te matchen. Nu zou de regex in het tweede deel worden uitgevoerd.

DEEL 2

^.*$

Uitleg:

  • ^ Beweert dat we aan het begin staan. dat wil zeggen, het komt overeen met alle beginlijnen behalve die in de regel hede. Bekijk hier de demo.
  • .* In de Multiline-modus komt . overeen met elk teken behalve nieuwe-regel- of regelteruglooptekens. En * zou het vorige teken nul of meer keren herhalen. Dus .* zou overeenkomen met de hele regel. Bekijk hier de demo.

    Hallo, waarom heb je .* toegevoegd in plaats van .+ ?

    Omdat .* overeenkomt met een lege regel, maar .+ niet met een lege regel. We willen alle regels matchen behalve hede , er kunnen ook lege regels in de invoer zijn. dus je moet .* gebruiken in plaats van .+ . .+ zou het vorige teken een of meerdere keren herhalen. Zie .* komt overeen met een lege regel hier.

  • $ Einde van de lijnanker is hier niet nodig.


Antwoord 22

Het is wellicht beter te onderhouden om twee regexen in uw code te gebruiken, één om de eerste overeenkomst te doen, en als deze overeenkomt, voer dan de tweede regex uit om te controleren op uitschieters die u wilt blokkeren, bijvoorbeeld ^.*(hede).* zorg dan voor de juiste logica in je code.

Ok, ik geef toe dat dit niet echt een antwoord is op de geposte vraag en het kan ook iets meer verwerking vergen dan een enkele regex. Maar voor ontwikkelaars die hier kwamen op zoek naar een snelle noodoplossing voor een uitschieter, mag deze oplossing niet over het hoofd worden gezien.


Antwoord 23

De TXR-taal ondersteunt regex-negatie.

$ txr -c '@(repeat)
@{nothede /~hede/}
@(do (put-line nothede))
@(end)'  Input

Een ingewikkelder voorbeeld: vergelijk alle regels die beginnen met a en eindigen met z, maar bevatten niet de substring hede:

$ txr -c '@(repeat)
@{nothede /a.*z&~.*hede.*/}
@(do (put-line nothede))
@(end)' -
az         <- echoed
az
abcz       <- echoed
abcz
abhederz   <- not echoed; contains hede
ahedez     <- not echoed; contains hede
ace        <- not echoed; does not end in z
ahedz      <- echoed
ahedz

Regex-ontkenning is op zichzelf niet erg handig, maar als je ook een intersectie hebt, wordt het interessant, omdat je een volledige set booleaanse setbewerkingen hebt: je kunt “de set die hiermee overeenkomt uitdrukken, behalve dingen die daarmee overeenkomen “.


Antwoord 24

De onderstaande functie zal u helpen om de gewenste output te krijgen

<?PHP
      function removePrepositions($text){
            $propositions=array('/\bfor\b/i','/\bthe\b/i'); 
            if( count($propositions) > 0 ) {
                foreach($propositions as $exceptionPhrase) {
                    $text = preg_replace($exceptionPhrase, '', trim($text));
                }
            $retval = trim($text);
            }
        return $retval;
    }
?>

Antwoord 25

Ik wilde nog een voorbeeld toevoegen voor als je een volledige regel probeert te matchen die string X bevat, maar niet ook string Y.

Laten we bijvoorbeeld zeggen dat we willen controleren of onze URL / string "tasty-treats" bevat, zolang deze niet ook "chocolade" overal.

Dit regex-patroon zou werken (werkt ook in JavaScript)

^(?=.*?tasty-treats)((?!chocolate).)*$

(globaal, meerregelige vlaggen in voorbeeld)

Interactief voorbeeld: https://regexr.com/53gv4

Wedstrijden

(Deze url’s bevatten "lekkernijen" en bevatten ook geen "chocolade")

  • example.com/tasty-treats/strawberry-ice-cream
  • example.com/desserts/tasty-treats/banana-pudding
  • example.com/tasty-treats-overview

Komt niet overeen

(Deze url’s bevatten ergens “chocolade” – dus ze komen niet overeen, ook al bevatten ze “tasty-traktaties”)

  • example.com/tasty-treats/chocolade-cake
  • example.com/home-cooking/oven-roasted-chicken
  • example.com/tasty-treats/banana-chocolate-fudge
  • example.com/desserts/chocolate/tasty-treats
  • example.com/chocolate/tasty-treats/desserts

Antwoord 26

^((?!hede).)*$ is een elegante oplossing, behalve dat het tekens verbruikt en je het niet kunt combineren met andere criteria. Stel bijvoorbeeld dat u wilde controleren op de niet-aanwezigheid van ‘hede’ en de aanwezigheid van ‘haha’. Deze oplossing zou werken omdat het geen tekens gebruikt:

^(?!.*\bhede\b)(?=.*\bhaha\b) 

Antwoord 27

Zolang u te maken heeft met lijnen, markeert u gewoon de negatieve overeenkomsten en richt u zich op de rest.

In feite gebruik ik deze truc met sed omdat ^((?!hede).)*$ er niet door wordt ondersteund.

Voor de gewenste output

  1. Markeer de negatieve overeenkomst: (bijv. regels met hede), met een teken dat helemaal niet in de hele tekst voorkomt. Een emoji zou hiervoor waarschijnlijk een goede keuze kunnen zijn.

    s/(.*hede)/??\1/g
    
  2. Target de rest (de ongemarkeerde strings: bijv. regels zonder hede). Stel dat u alleen het doel wilt behouden en de rest wilt verwijderen (zoals u wilt):

    s/^??.*//g
    

Voor een beter begrip

Stel dat u het doel wilt verwijderen:

  1. Markeer de negatieve overeenkomst: (bijv. regels met hede), met een teken dat helemaal niet in de hele tekst voorkomt. Een emoji zou hiervoor waarschijnlijk een goede keuze kunnen zijn.

    s/(.*hede)/??\1/g
    
  2. Target de rest (de ongemarkeerde strings: bijv. regels zonder hede). Stel dat u het doel wilt verwijderen:

    s/^[^??].*//g
    
  3. Verwijder het teken:

    s/??//g
    

Antwoord 28

Hoe de backtracking control-werkwoorden van PCRE te gebruiken om een ​​regel te matchen die geen woord bevat

Hier is een methode die ik nog niet eerder heb gebruikt:

/.*hede(*COMMIT)^|/

Hoe het werkt

Eerst probeert het “hede” ergens in de regel te vinden. Als dit lukt, vertelt (*COMMIT) de engine op dit punt om niet alleen niet terug te gaan in het geval van een storing, maar ook om in dat geval geen verdere matching te proberen. Vervolgens proberen we iets te matchen dat onmogelijk kan matchen (in dit geval ^).

Als een regel geen “hede” bevat, komt het tweede alternatief, een leeg subpatroon, met succes overeen met de onderwerpreeks.

Deze methode is niet efficiënter dan een negatieve blik vooruit, maar ik dacht ik gooi het hier maar op voor het geval iemand het handig vindt en er een gebruik voor vindt voor andere, interessantere toepassingen.


Antwoord 29

Een eenvoudigere oplossing is om de not-operator te gebruiken!

Uw if-statement moet overeenkomen met ‘bevat’ en niet met ‘uitgesloten’.

var contains = /abc/;
var excludes =/hede/;
if(string.match(contains) && !(string.match(excludes))){  //proceed...

Ik geloof dat de ontwerpers van RegEx anticipeerden op het gebruik van niet-operators.


Antwoord 30

Misschien vind je dit op Google terwijl je probeert een regex te schrijven die in staat is om segmenten van een regel te matchen (in tegenstelling tot hele regels) die geen een subtekenreeks bevatten. Het kostte me een tijdje om erachter te komen, dus ik zal het delen:

Gegeven een string:

<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

Ik wil overeenkomen met <span>-tags die de substring “slecht” niet bevatten.

/<span(?:(?!bad).)*?> komt overeen met <span class=\"good\"> en <span class=\"ugly\">.

Merk op dat er twee sets (lagen) haakjes zijn:

  • De binnenste is voor de negatieve vooruitblik (het is geen capture-groep)
  • De buitenste werd door Ruby geïnterpreteerd als een capture-groep, maar we willen niet dat het een capture-groep is, dus ik heb toegevoegd ?: aan het begin en het wordt niet langer geïnterpreteerd als een capture-groep.

Demo in Ruby:

s = '<span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>'
s.scan(/<span(?:(?!bad).)*?>/)
# => ["<span class=\"good\">", "<span class=\"ugly\">"]

LEAVE A REPLY

Please enter your comment!
Please enter your name here

12 + thirteen =

Other episodes