Expression régulière correspondant à une ligne ne contenant pas de mot?

Je sais qu’il est possible de faire correspondre un mot, puis d’inverser les correspondances à l’aide d’autres outils (par exemple, grep -v ). Cependant, j’aimerais savoir s’il est possible de faire correspondre des lignes qui ne contiennent pas un mot spécifique (par exemple, hede) en utilisant une expression régulière.

Consortingbution:

 hoho hihi haha hede 

Code:

 grep "" input 

Sortie désirée:

 hoho hihi haha 

La notion que regex ne supporte pas la correspondance inverse n’est pas tout à fait vraie. Vous pouvez reproduire ce comportement en utilisant des recherches négatives:

 ^((?!hede).)*$ 

Le regex ci-dessus correspondra à n’importe quelle chaîne ou ligne sans saut de ligne, ne contenant pas la chaîne (sub) ‘hede’. Comme mentionné, ce n’est pas quelque chose que regex est “bon” à (ou devrait faire), mais quand même, c’est possible.

Et si vous devez également faire correspondre les caractères de saut de ligne, utilisez le modificateur DOT-ALL (le fin du schéma suivant):

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

ou l’utiliser en ligne:

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

(où /.../ sont les délimiteurs de regex, c’est-à-dire ne faisant pas partie du motif)

Si le modificateur DOT-ALL n’est pas disponible, vous pouvez reproduire le même comportement avec la classe de caractères [\s\S] :

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

Explication

Une chaîne est juste une liste de n caractères. Avant et après chaque personnage, il y a une chaîne vide. Donc, une liste de n caractères aura n+1 chaînes vides. Considérons la chaîne "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 

où les e sont les chaînes vides. La regex (?!hede). regarde en avant pour voir s’il n’y a pas de sous-chaîne "hede" à voir, et si c’est le cas (donc quelque chose d’autre est vu), alors le . (point) correspondra à n’importe quel caractère sauf un saut de ligne. Les renvois sont également appelés assertions de largeur nulle car ils ne consumnt aucun caractère. Ils ne font qu’affirmer / valider quelque chose.

Donc, dans mon exemple, chaque chaîne vide est d’abord validée pour voir s’il n’y a pas de "hede" en avance, avant qu’un caractère ne soit consommé par le . (point). La regex (?!hede). fera cela une seule fois, donc il est enveloppé dans un groupe et répété zéro ou plusieurs fois: ((?!hede).)* . Enfin, le début et la fin de l’entrée sont ancrés pour s’assurer que toute l’entrée est ^((?!hede).)*$ : ^((?!hede).)*$

Comme vous pouvez le voir, l’entrée "ABhedeCD" échouera car sur e3 , la regex (?!hede) échoue (il y a "hede" en avance!).

Notez que la solution à ne commence pas par «hede» :

 ^(?!hede).*$ 

est généralement beaucoup plus efficace que la solution ne contient pas «hede» :

 ^((?!hede).)*$ 

Le premier vérifie «hede» uniquement à la première position de la chaîne d’entrée, plutôt qu’à chaque position.

Si vous ne l’utilisez que pour grep, vous pouvez utiliser grep -v hede pour obtenir toutes les lignes ne contenant pas hede.

ETA: En relisant la question, grep -v est probablement ce que vous vouliez dire par “options d’outils”.

Répondre:

 ^((?!hede).)*$ 

Explication:

^ le début de la chaîne, ( grouper et capturer à \ 1 (0 fois ou plus (correspondant au plus grand nombre possible)),
(?! regarde devant pour voir s’il n’y en a pas,

hede ta ficelle,

) fin du délai,. tout caractère sauf \ n,
)* end of \ 1 (Remarque: comme vous utilisez un quantificateur sur cette capture, seule la dernière répétition du motif capturé sera stockée dans \ 1)
$ avant une option \ n et la fin de la chaîne

Les réponses données sont parfaitement correctes, juste un point académique:

Les expressions régulières au sens de l’informatique théorique NE SONT PAS ABLEES le font comme ça. Pour eux, cela devait ressembler à ceci:

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

Cela ne fait qu’un match complet. Le faire pour des sous-matches serait même plus gênant.

Si vous souhaitez que le test regex échoue uniquement si la chaîne entière correspond, les éléments suivants fonctionneront:

 ^(?!hede$).* 

par exemple – Si vous souhaitez autoriser toutes les valeurs sauf “foo” (ie “foufou”, “barfoo” et “foobar” passera, mais “foo” échouera), utilisez: ^(?!foo$).*

Bien sûr, si vous recherchez une égalité exacte , une meilleure solution générale dans ce cas est de vérifier l’égalité des chaînes, c.-à-d.

 myStr !== 'foo' 

Vous pouvez même mettre la négation en dehors du test si vous avez besoin de fonctionnalités de regex (ici, insensibilité à la casse et correspondance des plages):

 !/^[af]oo$/i.test(myStr) 

La solution regex en haut peut être utile dans les cas où un test regex positif est requirejs (peut-être par une API).

Voici une bonne explication de la raison pour laquelle il n’est pas facile de nier une expression rationnelle arbitraire. Je suis cependant d’accord avec les autres réponses: si cela n’est pas une question hypothétique, une regex n’est pas le bon choix ici.

FWIW, puisque les langages réguliers (aka langages rationnels) sont fermés en complémentation, il est toujours possible de trouver une expression régulière (une expression rationnelle) qui annule une autre expression. Mais peu d’outils implémentent cela.

Vcsn supporte cet opérateur ( dénoté {c} , postfix).

Vous définissez d’abord le type de vos expressions: les étiquettes sont des lettres ( lal_char ) à choisir par exemple (définir l’alphabet lorsque vous lal_char complémentation est très important) et la “valeur” calculée pour chaque mot est juste un booléen: true le mot est accepté, false , rejeté.

En Python:

 In [5]: import vcsn c = vcsn.context('lal_char(az), 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} → 𝔹 

alors vous entrez votre expression:

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

convertir cette expression en automate:

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

L'automate correspondant

enfin, reconvertissez cet automate en une expression simple.

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

+ est généralement noté | , \e indique le mot vide et [^] est généralement écrit . (n’importe quel caractère). Donc, avec un peu de réécriture ()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).* .

Vous pouvez voir cet exemple ici et essayer Vcsn en ligne.

Repères

J’ai décidé d’évaluer certaines des options présentées et de comparer leurs performances, ainsi que d’utiliser de nouvelles fonctionnalités. Benchmarking sur .NET Regex Engine: http://regexhero.net/tester/

Texte de référence:

Les 7 premières lignes ne doivent pas correspondre, car elles contiennent l’expression recherchée, tandis que les 7 lignes inférieures doivent correspondre!

 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. une 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. en 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. 

Résultats:

Les résultats sont des itérations par seconde, la médiane de 3 cycles – plus grand nombre = meilleur

 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 

Comme .NET ne supporte pas les verbes d’action (* FAIL, etc.), je n’ai pas pu tester les solutions P1 et P2.

Résumé:

J’ai essayé de tester la plupart des solutions proposées, certaines optimisations sont possibles pour certains mots. Par exemple, si les deux premières lettres de la chaîne de recherche ne sont pas identiques, la réponse 03 peut être étendue à ^(?>[^R]+|R+(?!egex Hero))*$ entraînant un faible gain de performance.

Mais la solution la plus rapide et la plus lisible semble être 05 utilisant un énoncé conditionnel ou 04 avec le quantificateur potentiel. Je pense que les solutions Perl devraient être encore plus rapides et plus facilement lisibles.

Avec la recherche négative, l’expression régulière peut correspondre à quelque chose qui ne contient pas de motif spécifique. Ceci est répondu et expliqué par Bart Kiers. Bonne explication!

Cependant, avec la réponse de Bart Kiers, la partie “lookahead” testera 1 à 4 caractères en avant tout en faisant correspondre n’importe quel caractère. Nous pouvons éviter cela et laisser la partie de vérification vérifier le texte entier, s’assurer qu’il n’y a pas de «hede», et alors la partie normale (. *) Peut manger tout le texte en même temps.

Voici la regex améliorée:

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

Notez le quantificateur paresseux dans la partie préparsing négative est facultative, vous pouvez utiliser (*) quantificateur gourmand à la place, en fonction de vos données (*): si « Hede » ne présente et dans la moitié début du texte, le quantificateur paresseux peut Être plus rapide; sinon, le quantificateur gourmand sera plus rapide. Cependant, si «hede» n’est pas présent, les deux seraient égaux en lent.

Voici le code de démonstration .

Pour plus d’informations sur lookahead, s’il vous plaît consulter le grand article: Mastering Lookahead et Lookbehind .

En outre, consultez RegexGen.js , un générateur d’expressions régulières JavaScript qui aide à construire des expressions régulières complexes. Avec RegexGen.js, vous pouvez construire le regex de manière plus lisible:

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

Pas de regex, mais j’ai trouvé logique et utile d’utiliser des greps série avec pipe pour éliminer le bruit.

par exemple. rechercher un fichier de configuration apache sans tous les commentaires-

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

et

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

La logique de serial grep est (pas un commentaire) et (correspond à dir)

avec cela, vous évitez de tester un lookahead sur chaque position:

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

équivalent à (pour .net):

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

Vieille réponse:

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

Voici comment je le ferais:

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

Précis et plus efficace que les autres réponses. Il met en œuvre la technique d’efficacité «dérouler la boucle» de Friedl et nécessite beaucoup moins de retour en arrière.

Afor susmentionné (?:(?!hede).)* Est génial car il peut être ancré.

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

Mais ce qui suit suffirait dans ce cas:

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

Cette simplification est prête à avoir des clauses “ET” ajoutées:

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

Si vous souhaitez faire correspondre un caractère pour annuler un mot similaire à la classe de caractère négatif:

Par exemple, une chaîne:

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

Ne pas utiliser:

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

Utilisation:

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

Notez "(?!bbb)." n’est ni lookbeead ni lookahead, c’est lookcurrent, par exemple:

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

L’OP n’a pas spécifié ou Tag le poste pour indiquer le contexte (langage de programmation, éditeur, outil) dans lequel le Regex sera utilisé.

Pour moi, j’ai parfois besoin de le faire en éditant un fichier en utilisant Textpad .

Textpad prend en charge certains Regex, mais ne supporte pas lookahead ou lookbehind, il faut donc quelques étapes.

Si je cherche à conserver toutes les lignes qui ne contiennent pas la chaîne hede , je le ferais comme ceci:

1. Recherchez / remplacez le fichier entier pour append un “Tag” unique au début de chaque ligne contenant du texte.

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

2. Supprimez toutes les lignes contenant la chaîne hede (la chaîne de remplacement est vide):

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

3. À ce stade, toutes les lignes restantes NE contiennent PAS la chaîne hede . Supprimez l’unique “Tag” de toutes les lignes (la chaîne de remplacement est vide):

  Search ssortingng:< @#-unique-#@> Replace ssortingng: Replace-all 

Vous avez maintenant le texte original avec toutes les lignes contenant la chaîne hede enlevée.


Si je cherche à faire quelque chose d’autre que des lignes qui ne contiennent pas la chaîne hede , je le ferais comme ceci:

1. Recherchez / remplacez le fichier entier pour append un “Tag” unique au début de chaque ligne contenant du texte.

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

2. Pour toutes les lignes contenant la chaîne hede , supprimez l’unique “Tag”:

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

3. A ce stade, toutes les lignes qui commencent par l’unique “Tag”, NE contiennent PAS la chaîne hede . Je peux maintenant faire mon Something Else à seulement ces lignes.

4. Une fois terminé, je supprime l’unique “Tag” de toutes les lignes (la chaîne de remplacement est vide):

  Search ssortingng:< @#-unique-#@> Replace ssortingng: Replace-all 

Par verbe PCRE (*SKIP)(*F)

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

Cela saute complètement la ligne qui contient la chaîne exacte hede et correspond à toutes les lignes restantes.

DEMO

Exécution des pièces:

Considérons le regex ci-dessus en le divisant en deux parties.

  1. Partie avant le | symbole. La partie ne doit pas être appariée .

     ^hede$(*SKIP)(*F) 
  2. Partie après le | symbole. La partie doit être appariée .

     ^.*$ 

PARTIE 1

Le moteur Regex commencera son exécution à partir de la première partie.

 ^hede$(*SKIP)(*F) 

Explication:

  • ^ Affirme que nous sums au départ.
  • hede Correspond à la chaîne hede
  • $ Affirme que nous sums à la fin de la ligne.

Ainsi, la ligne qui contient la chaîne hede serait mise en correspondance. Une fois que le moteur d’expressions rationnelles voit ce qui suit (*SKIP)(*F) ( Remarque: Vous pouvez écrire (*F) comme (*FAIL) ) verbe, il saute et fait échouer la correspondance. | L’altération appelée ou l’opérateur logique OU ajouté à côté du verbe PCRE qui correspond à toutes les limites existe entre chaque caractère de toutes les lignes, sauf que la ligne contient la chaîne exacte hede . Voir la démo ici . En d’autres termes, il essaie de faire correspondre les caractères de la chaîne restante. Maintenant, le regex dans la deuxième partie serait exécuté.

PARTIE 2

 ^.*$ 

Explication:

  • ^ Affirme que nous sums au départ. c’est-à-dire qu’il correspond à toutes les lignes hede sauf celle de la ligne hede . Voir la démo ici .
  • .* En mode multiligne,. correspondrait à tous les caractères, à l’exception des caractères de retour à la ligne ou de retour à la ligne. Et * répéterait le caractère précédent zéro ou plusieurs fois. Donc, .* correspondrait à toute la ligne. Voir la démo ici .

    Hey pourquoi tu as ajouté. * Au lieu de. +?

    Car .* Correspondrait à une ligne vide mais .+ Ne correspondrait pas à un blanc. Nous voulons faire correspondre toutes les lignes sauf hede , il peut y avoir une possibilité de lignes vides également dans l’entrée. vous devez donc utiliser .* au lieu de .+ . .+ répète le caractère précédent une ou plusieurs fois. Voir .* Correspond à une ligne vide ici .

  • $ fin de la ligne d’ancrage n’est pas nécessaire ici.

Depuis l’introduction de ruby-2.4.1, nous pouvons utiliser le nouvel opérateur absent dans les expressions régulières de Ruby.

de la doc officielle

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

Ainsi, dans votre cas ^(?~hede)$ fait le travail pour vous

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

Puisque personne d’autre n’a répondu directement à la question posée , je le ferai.

La réponse est qu’avec POSIX grep , il est impossible de satisfaire littéralement cette requête:

 grep "Regex for doesn't contain hede" Input 

La raison en est que POSIX grep est uniquement requirejs pour fonctionner avec les expressions régulières de base , qui ne sont tout simplement pas assez puissantes pour accomplir cette tâche (elles ne sont pas capables d’parsingr les langages réguliers, faute d’alternance et de regroupement).

Cependant, GNU grep implémente les extensions qui le permettent. En particulier, \| est l’opérateur d’alternance dans l’implémentation de BRE par GNU, et \( et \) sont les opérateurs de regroupement. Si votre moteur d’expression régulière prend en charge l’alternance, les expressions de parenthèses négatives, le regroupement et l’écanvas de Kleene, et est capable de s’ancrer au début et à la fin de la chaîne, c’est tout ce dont vous avez besoin pour cette approche.

Avec GNU grep , ce serait quelque chose comme:

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

(trouvé avec Graal et quelques optimisations supplémentaires faites à la main).

Vous pouvez également utiliser un outil qui implémente les expressions régulières étendues , comme egrep , pour supprimer les barres obliques inverses:

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

Voici un script pour le tester (notez qu’il génère un fichier testinput.txt dans le répertoire courant):

 #!/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 <  

Dans mon système, il imprime:

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

comme prévu.

Pour ceux qui s'intéressent aux détails, la technique employée consiste à convertir l'expression régulière qui correspond au mot en un automate fini, puis à inverser l'automate en changeant chaque état d'acceptation en non-acceptation et vice versa, puis en convertissant l'AF résultant en une expression régulière.

Enfin, comme tout le monde l’a noté, si votre moteur d’expression régulière prend en charge la lecture négative, cela simplifie beaucoup la tâche. Par exemple, avec GNU grep:

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

Mise à jour: J'ai récemment trouvé l'excellente bibliothèque FormalTheory de Kendall Hopkins, écrite en PHP, qui fournit une fonctionnalité similaire à Grail. Using it, and a simplifier written by myself, I've been able to write an online generator of negative regular expressions given an input phrase (only alphanumeric and space characters currently supported): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

For hede it outputs:

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

which is equivalent to the above.

It may be more maintainable to two regexes in your code, one to do the first match, and then if it matches run the second regex to check for outlier cases you wish to block for example ^.*(hede).* then have appropriate logic in your code.

OK, I admit this is not really an answer to the posted question posted and it may also use slightly more processing than a single regex. But for developers who came here looking for a fast emergency fix for an outlier case then this solution should not be overlooked.

The TXR Language supports regex negation.

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

A more complicated example: match all lines that start with a and end with z , but do not contain the subssortingng 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 negation is not particularly useful on its own but when you also have intersection, things get interesting, since you have a full set of boolean set operations: you can express "the set which matches this, except for things which match that".

The below function will help you get your desired output

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

A simpler solution is to use the not operator !

Your if statement will need to match “contains” and not match “excludes”.

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

I believe the designers of RegEx anticipated the use of not operators.

How to use PCRE’s backtracking control verbs to match a line not containing a word

Here’s a method that I haven’t seen used before:

 /.*hede(*COMMIT)^|/ 

Comment ça marche

First, it sortinges to find “hede” somewhere in the line. If successful, at this point, (*COMMIT) tells the engine to, not only not backtrack in the event of a failure, but also not to attempt any further matching in that case. Then, we try to match something that cannot possibly match (in this case, ^ ).

If a line does not contain “hede” then the second alternative, an empty subpattern, successfully matches the subject ssortingng.

This method is no more efficient than a negative lookahead, but I figured I’d just throw it on here in case someone finds it nifty and finds a use for it for other, more interesting applications.

Maybe you’ll find this on Google while trying to write a regex that is able to match segments of a line (as opposed to entire lines) which do not contain a subssortingng. Tooke me a while to figure out, so I’ll share:

Given a ssortingng: barfoobaz

I want to match tags which do not contain the subssortingng “bad”.

/ will match and .

Notice that there are two sets (layers) of parentheses:

  • The innermost one is for the negative lookahead (it is not a capture group)
  • The outermost was interpreted by Ruby as capture group but we don’t want it to be a capture group, so I added ?: at it’s beginning and it is no longer interpreted as a capture group.

Demo in Ruby:

 s = 'barfoobaz' s.scan(//) # => ["", ""] 

I don’t understand the need for complex regex or even lookaheads here :

 /hede|^(.*)$/gm 

Don’t put in a capturing group the thing you don’t want, but use one for everything else. This will match all lines that don’t contain “hede”.

With ConyEdit , you can use the command line cc.gl !/hede/ to get lines that do not contain the regex matching, or use the command line cc.dl /hede/ to delete lines that contain the regex matching. They have the same result.