Question

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

Saisir:

hoho
hihi
haha
hede

Code:

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

Sortie désirée:

hoho
hihi
haha
Était-ce utile?

La solution

L'idée que regex ne prend pas en charge la correspondance inverse n'est pas tout à fait vraie. Vous pouvez imiter ce comportement en utilisant des solutions négatives:

^((?!hede).)*$

L'expression rationnelle ci-dessus correspond à toute chaîne ou ligne sans saut de ligne, pas contenant la chaîne (sous) "hede". Comme mentionné précédemment, ce n'est pas quelque chose de regex est & "Bon &"; at (ou devrait faire), mais cela reste possible .

Si vous devez également faire correspondre les caractères de fin de ligne, utilisez le modificateur DOT-ALL (le dernier s dans le motif suivant):

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

ou utilisez-le en ligne:

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

(où les /.../ sont les délimiteurs de regex, c'est-à-dire qui ne font pas partie du modèle)

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

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

Explication

Une chaîne est simplement une liste de n caractères. Avant et après chaque caractère, il y a une chaîne vide. Ainsi, une liste de n+1 caractères aura "ABhedeCD" des chaînes vides. Considérons la chaîne e:

    ┌──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┬───┬──┐
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 (?!hede). sont les chaînes vides. La regex "hede" regarde en avant pour voir s'il n'y a pas de sous-chaîne . à voir, et si c'est le cas (si quelque chose d'autre est vu), alors le ((?!hede).)* (point) correspondra à tout caractère sauf un saut de ligne . Les références indirectes sont également appelées assertions de largeur nulle car elles ne consomment aucun caractère. Ils ne font qu'affirmer / valider quelque chose.

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

Comme vous pouvez le constater, l'entrée <=> échouera car, sur <=>, l'expression rationnelle <=> échoue ( il y a <=> devant vous!).

Autres conseils

Notez que la solution pour ne commence pas par & # 8220; hede & # 8221; :

^(?!hede).*$

est généralement beaucoup plus efficace que la solution pour ne pas contenir & # 8220; hede & # 8221; :

^((?!hede).)*$

L'ancien vérifie & # 8220; hede & # 8221; uniquement à la première position de la chaîne d'entrée & # 8217; plutôt qu'à toutes les positions.

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

ETA Oh, relisez la question, grep -v correspond probablement à ce que vous entendiez par & "Options pour les outils &";

.

Réponse:

^((?!hede).)*$

Explication:

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

hede votre chaîne,

) fin de la recherche anticipée, . tout caractère sauf \ n,
)* fin de \ 1 (Remarque: comme vous utilisez un quantificateur pour cette capture, seule la DERNIÈRE répétition du motif capturé sera stockée dans \ 1)

$ avant un \ n optionnel et la fin de la chaîne

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

Les expressions régulières dans le sens des sciences informatiques théoriques NE SONT PAS CAPABLES faites-le comme ceci. Pour eux, cela devait ressembler à quelque chose comme ça:

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

Ceci ne fait qu'une correspondance complète. Le faire pour des sous-matchs serait encore plus délicat.

Si vous souhaitez que le test de regex seulement échoue si la chaîne entière correspond, les opérations suivantes fonctionneront:

^(?!hede$).*

par exemple. - Si vous souhaitez autoriser toutes les valeurs sauf & Quot; foo & Quot; (c.-à-d. & "; foofoo &"; & "barfoo &" et & "foobar &" passera, mais & "foo quot; échouera), utilisez: ^(?!foo$).*

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

myStr !== 'foo'

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

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

La solution de regex en haut de cette réponse peut être utile, cependant, dans les situations où un test de regex positif est requis (peut-être par une API).

FWIW, étant donné que les langages normaux (ou rationnels) sont fermés par complémentation, il est toujours possible de trouver une expression régulière (ou expression rationnelle) qui nie une autre expression. Mais peu d’outils implémentent cela.

Vcsn prend en charge cet opérateur (qu'il désigne {c}, postfix ).

Vous définissez d’abord le type de vos expressions: les libellés sont des lettres (lal_char) à sélectionner, par exemple de a à z (définir l’alphabet lorsque vous travaillez avec la complémentation est bien sûr très important), et la " valeur " calculé pour chaque mot est simplement un booléen: true le mot est accepté, false, rejeté.

En 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} → 𝔹

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 désigne 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 essayez de Vcsn en ligne.

Voici une bonne explication de la raison pour laquelle il n'est pas facile d'annuler une regex arbitraire. Je suis cependant d’accord avec les autres réponses: si c’est autre chose qu’une question hypothétique, alors une expression régulière n’est pas le bon choix ici.

Avec un préfixe négatif, une 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. Grande explication!

Cependant, avec la réponse de Bart Kiers, la partie en attente de test testera 1 à 4 caractères à l’avance tout en faisant correspondre un seul caractère. Nous pouvons éviter cela et laisser la partie attentive vérifier le texte en entier, s'assurer qu'il n'y a pas de 'hede', et ensuite la partie normale (. *) Peut tout manger en même temps.

Voici la regex améliorée:

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

Notez que le quantificateur paresseux (*?) dans la partie lookahead négatif est optionnel, vous pouvez utiliser un quantificateur glouton (*) à la place, en fonction de vos données: si 'hede' est présent et au début du texte, le quantificateur paresseux peut être plus rapide; sinon, le quantificateur glouton sera plus rapide. Toutefois, si "hede" n'est pas présent, les deux seront égaux.

Voici le code de démonstration .

Pour plus d'informations sur lookahead, consultez l'excellent article: Maîtriser l'apparence et l'apparence .

Consultez également le RegexGen.js , un générateur d’expressions régulières JavaScript qui permet de créer des expressions régulières complexes. Avec RegexGen.js, vous pouvez construire l’expression rationnelle 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',
                                    //   i.e., anything contains 'hede'
    ), 
    _.endOfLine()
);

Points de repère

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. Analyse comparative du moteur .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, alors que les 7 lignes les plus basses 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.

Résultats:

Les résultats sont exprimés en itérations par seconde comme la médiane de 3 analyses - 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

Etant donné que .NET ne prend pas en charge les actions Verbes (* 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))*$ résultant en un petit gain de performance.

Mais la solution la plus lisible et la plus rapide en termes de performances semble être 05 avec une instruction conditionnelle ou 04 avec le quantificateur possesif. Je pense que les solutions Perl devraient être encore plus rapides et plus faciles à lire.

Pas une regex, mais j'ai trouvé logique et utile d'utiliser des greps sériels 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 la série grep est (pas un commentaire) et (correspond à dir)

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

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

équivalent à (pour .net):

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

Ancienne réponse:

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

Ce qui précède (?:(?!hede).)* est formidable car il peut être ancré.

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

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

Mais les éléments suivants suffiraient dans ce cas:

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

Cette simplification est prête à avoir " ET " clauses ajoutées:

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

Voici comment je le ferais:

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

Précis et plus efficace que les autres réponses. Il implémente la technique d'efficacité de & «Dérouler la boucle» de de Friedl et nécessite beaucoup moins de retours en arrière.

Si vous souhaitez associer un caractère à un mot similaire à celui d'une classe de caractères:

Par exemple, une chaîne:

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

Ne pas utiliser:

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

Utiliser:

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

Notez que "(?!bbb)." n'est ni à la recherche ni à l'avance, il est au courant, par exemple:

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

Le PO n'a pas précisé ou Étiqueter le message pour indiquer le contexte (langage de programmation, éditeur, outil) dans lequel la Regex sera utilisée.

Pour moi, j'ai parfois besoin de le faire lors de l'édition d'un fichier en utilisant Textpad.

Textpad prend en charge certaines expressions régulières, mais ne prend pas en charge l'anticipation ou l'analyse derrière, cela prend donc quelques étapes.

Si je cherche à conserver toutes les lignes qui Ne pas contient la chaîne hede, je ferais comme ça :

1.Recherchez/remplacez l'intégralité du fichier pour ajouter une « balise » unique au début de chaque ligne contenant du texte.

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

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

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

3.À ce stade, toutes les lignes restantes Ne pas contient la chaîne hede.Supprimez le "Tag" unique de toutes les lignes (la chaîne de remplacement est vide) :

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

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


Si je cherche à Faire autre chose aux seules lignes qui Ne pas contient la chaîne hede, je ferais comme ça :

1.Recherchez/remplacez l'intégralité du fichier pour ajouter une « balise » unique au début de chaque ligne contenant du texte.

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

2.Pour toutes les lignes contenant la chaîne hede, supprimez le "Tag" unique :

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

3.À ce stade, toutes les lignes commençant par l'unique "Tag", Ne pas contient la chaîne hede.Je peux maintenant faire mon Autre chose uniquement à ces lignes.

4.Quand j'ai terminé, je supprime le "Tag" unique de toutes les lignes (la chaîne de remplacement est vide) :

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

Un, à mon avis, une variante plus lisible de la première réponse:

^(?!.*hede)

Fondamentalement, & "correspond au début de la ligne si et seulement si elle ne contient pas" hede "dedans &"; - si l'exigence est traduite presque directement en regex.

Bien sûr, il est possible d'avoir plusieurs exigences d'échec:

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

Détails: L'ancrage ^ assure que le moteur des expressions rationnelles ne réessaie pas la correspondance à chaque emplacement de la chaîne, ce qui correspondrait à chaque chaîne.

L'ancre ^ au début est censé représenter le début de la ligne. L'outil grep fait correspondre chaque ligne une à la fois. Dans les contextes dans lesquels vous travaillez avec une chaîne multiligne, vous pouvez utiliser le & "; M &"; drapeau:

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

ou

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

Depuis l'introduction de ruby-2.4.1, nous pouvons utiliser le nouveau opérateur absent < dans les expressions régulières de Ruby & # 8217;

tiré du doc

(?~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"]

Par le verbe PCRE (*SKIP)(*F)

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

Ceci ignorerait 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 la regex ci-dessus en la scindant en deux parties.

  1. Partie précédant le symbole |. La partie ne doit pas correspondre .

    ^hede$(*SKIP)(*F)
    
  2. Partie après le symbole ^. La partie doit correspondre .

    ^.*$
    

PARTIE 1

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

<*>

Explication:

  • $ affirme que nous sommes au début.
  • (*F) correspond à la chaîne (*FAIL)
  • .* affirme que nous sommes en fin de ligne.

La ligne contenant la chaîne . sera donc mise en correspondance. Une fois que le moteur des expressions rationnelles voit le * ( Remarque: vous pouvez écrire .+ sous la forme d'un verbe <=> ), il est ignoré et la correspondance échoue. <=> opérateur appelé altération ou OU logique ajouté à côté du verbe PCRE qui correspond actuellement à toutes les limites existant entre chaque caractère de toutes les lignes sauf que la ligne contient la chaîne exacte <=>. Voir la démo ici . C'est-à-dire qu'il essaie de faire correspondre les caractères de la chaîne restante. Maintenant, la regex dans la deuxième partie serait exécutée.

PARTIE 2

<*>

Explication:

  • <=> affirme que nous sommes au début. c’est-à-dire qu’elle correspond à tous les débuts de ligne, à l’exception de celui de la ligne <=>. Voir la démo ici .
  • <=> En mode multiligne, <=> correspond à tout caractère sauf les caractères de retour à la ligne ou de retour à la ligne. Et <=> répéterait le caractère précédent zéro fois ou plus. Donc, <=> correspondrait à toute la ligne. Voir la démo ici .

    Hé pourquoi vous avez ajouté. * au lieu de. +?

    Parce que <=> correspondrait à une ligne vide mais <=> ne correspondra pas à une ligne vide. Nous voulons faire correspondre toutes les lignes sauf <=>, il est également possible que des lignes vides apparaissent é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 .

  • <=> L'ancre de fin de ligne n'est pas nécessaire ici.

Étant donné que personne d'autre n'a répondu directement à la question qui a été 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 \| est uniquement requis pour fonctionner avec 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’analyser les langues normales, en raison du manque d’alternance et de regroupement).

Cependant, GNU \( implémente des extensions qui le permettent. En particulier, \) est l'opérateur d'alternance dans la mise en œuvre de BRE par GNU, et egrep et testinput.txt sont les opérateurs de regroupement. Si votre moteur d’expression régulière prend en charge l’alternance, les expressions entre crochets, le regroupement et l’étoile Kleene, et s’ancre au début et à la fin de la chaîne, c’est tout ce dont vous avez besoin pour cette approche.

Avec GNU hede, 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 effectuées à la main).

Vous pouvez également utiliser un outil qui implémente Expressions régulières étendues , comme <=>, pour vous débarrasser des 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 <=> dans le répertoire en cours):

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

Dans mon système, il imprime:

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

comme prévu.

Pour les personnes intéressées par les détails, la technique utilisée consiste à convertir l’expression régulière qui correspond au mot en un automate fini, puis à inverser l’automate en modifiant chaque état d’acceptation en non-acceptation, et inversement, puis en convertissant le résultat obtenu. FA retour à une expression régulière.

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

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

Mise à jour: J'ai récemment découvert l'excellent FormalTheory bibliothèque de Kendall Hopkins. , écrit en PHP, qui fournit une fonctionnalité similaire à Graal. En l'utilisant, et avec un simplificateur écrit par moi-même, j'ai pu écrire un générateur en ligne d'expressions régulières négatives à partir d'une phrase d'entrée (seuls les caractères alphanumériques et les espaces actuellement pris en charge): http://www.formauri.es/personal/pgimeno/misc/non-match-regex/

Pour <=> il génère:

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

ce qui est équivalent à ce qui précède.

Il peut être plus facile de maintenir deux expressions rationnelles dans votre code, une pour faire la première correspondance, puis si elle correspond, exécutez la deuxième regex pour vérifier les cas aberrants que vous souhaitez bloquer, par exemple ^.*(hede).*, puis disposez de la logique appropriée votre code.

OK, j’admets qu’il ne s’agit pas vraiment d’une réponse à la question postée et qu’il peut également prendre un peu plus de temps de traitement qu’une simple expression régulière. Mais pour les développeurs qui sont venus ici à la recherche d’une solution rapide pour un cas aberrant, cette solution ne doit pas être négligée.

La langage TXR prend en charge la négation des expressions rationnelles.

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

Un exemple plus compliqué: correspond à toutes les lignes commençant par a et se terminant par z, mais ne contenant pas la sous-chaîne 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

La négation d'une expression rationnelle n'est pas particulièrement utile en soi, mais lorsque vous avez également une intersection, les choses deviennent intéressantes, car vous disposez d'un ensemble complet d'opérations sur les ensembles booléens: vous pouvez exprimer & "l'ensemble qui correspond à cela, sauf pour les choses qui correspondent à cette ".

La fonction ci-dessous vous aidera à obtenir le résultat souhaité

.
<?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;
    }


?>

Comment utiliser les verbes de contrôle de retour arrière de PCRE pour faire correspondre une ligne ne contenant pas un mot

Voici une méthode que je n'ai jamais vue utilisée auparavant:

/.*hede(*COMMIT)^|/

Comment ça marche

Tout d'abord, il essaie de trouver & "; hede &"; quelque part dans la ligne. En cas de succès, à ce stade, (*COMMIT) indique au moteur non seulement de ne pas revenir en arrière en cas de panne, mais également de ne pas tenter de correspondance ultérieure dans ce cas. Ensuite, nous essayons de faire correspondre quelque chose qui ne peut pas correspondre (dans ce cas, ^).

Si une ligne ne contient pas " hede " alors la deuxième alternative, un sous-modèle vide, correspond à la chaîne de sujet.

Cette méthode n’est pas plus efficace qu’un regard négatif, mais j’ai pensé que j’allais la mettre ici si c’était au cas où quelqu'un la trouverait chouette et la trouverait utile pour d’autres applications plus intéressantes.

Vous le trouverez peut-être sur Google lorsque vous essayez d'écrire une expression rationnelle capable de faire correspondre les segments d'une ligne (par opposition à des lignes entières) qui ne ne contient pas de sous-chaîne. Prends-moi un peu de temps pour comprendre, alors je vais partager:

Étant donné une chaîne: <span class="good">bar</span><span class="bad">foo</span><span class="ugly">baz</span>

Je veux faire correspondre les balises <span> qui ne contiennent pas la sous-chaîne & "bad &";.

.

/<span(?:(?!bad).)*?> correspondra à <span class=\"good\"> et <span class=\"ugly\">.

Notez qu'il existe deux ensembles (couches) de parenthèses:

  • La solution la plus interne est celle de la prévision négative (ce n'est pas un groupe de capture)
  • Ruby a interprété le groupe le plus externe comme un groupe de capture, mais nous ne voulons pas qu’il s’agisse d’un groupe de capture. C’est pourquoi j’ai ajouté?: au début, il n’est plus interprété comme un groupe de capture.

Démo en rubis:

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\">"]

Une solution plus simple consiste à utiliser le non-opérateur !

.

Votre déclaration si doit correspondre à & "contient &"; et ne correspond pas à & "; exclut &";

var contains = /abc/;
var excludes =/hede/;

if(string.match(contains) && !(string.match(excludes))){  //proceed...

Je crois que les concepteurs de RegEx ont prévu l’utilisation de non-opérateurs.

Avec ConyEdit , vous pouvez utiliser la ligne de commande cc.gl !/hede/ pour obtenir les lignes ne contenant pas l'expression régulière. correspondant ou utilisez la ligne de commande cc.dl /hede/ pour supprimer les lignes contenant la correspondance des expressions rationnelles. Ils ont le même résultat.

^ ((?! hede).) * $ est une solution élégante, sauf que, étant donné qu'il utilise des caractères, vous ne pourrez pas le combiner avec d'autres critères. Par exemple, supposons que vous vouliez vérifier la non-présence de & "; Hede &"; et la présence de & "haha. &"; Cette solution fonctionnerait car elle ne consommerait pas de caractères:

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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top