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, est-il possible de faire correspondre des lignes qui ne contiennent pas de mot spécifique, par exemple hede
en utilisant une expression régulière?
Contribution:
hoho
hihi
haha
hede
Code:
grep "<Regex for 'doesn't contain hede'>" input
Sortie désirée:
hoho
hihi
haha
regex
regex-negation
knaser
la source
la source
([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$)))*
:? L'idée est simple. Gardez la correspondance jusqu'à ce que vous voyiez le début de la chaîne indésirable, puis ne correspondez que dans les N-1 cas où la chaîne n'est pas terminée (où N est la longueur de la chaîne). Ces cas N-1 sont "h suivi de non-e", "il a suivi de non-d" et "hed suivi de non-e". Si vous avez réussi à passer ces N-1 cas, avec succès ne pas correspondre à la chaîne non désirée afin que vous puissiez commencer à chercher à[^h]*
nouveau^([^h]*(h([^e]|$)|he([^d]|$)|hed([^e]|$))?)*$
cela échoue lorsque les instances de "hede" sont précédées par des instances partielles de "hede" comme dans "hhede".Réponses:
L'idée que l'expression régulière ne prend pas en charge la correspondance inverse n'est pas entièrement vraie. Vous pouvez imiter ce comportement à l'aide de contournements négatifs:
L'expression régulière ci-dessus correspondra à n'importe quelle chaîne ou ligne sans saut de ligne, ne contenant pas la (sous) chaîne 'hede'. Comme mentionné précédemment, ce n'est pas quelque chose regex est « bon » à (ou devrait faire), mais encore, il est possible.
Et si vous devez également faire correspondre les caractères de saut de ligne, utilisez le modificateur DOT-ALL (la fin
s
dans le modèle suivant):ou utilisez-le en ligne:
(où
/.../
sont les délimiteurs d'expressions régulières, c'est-à-dire ne faisant 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]
:Explication
Une chaîne n'est qu'une liste de
n
caractères. Avant et après chaque caractère, il y a une chaîne vide. Ainsi, une liste den
caractères auran+1
des chaînes vides. Considérez la chaîne"ABhedeCD"
:où les
e
sont les chaînes vides. Le 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 ressemblances 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 en a pas
"hede"
, avant qu'un caractère ne soit consommé par le.
(point). Le regex(?!hede).
fera qu'une seule fois, il est enveloppé dans un groupe, et répété zéro ou plus:((?!hede).)*
. 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:^((?!hede).)*$
Comme vous pouvez le voir, l'entrée
"ABhedeCD"
échouera care3
, le regex(?!hede)
échoue (il y a"hede"
de l'avance!).la source
grep
que l'OP mentionne) avec support regex ont tous des fonctionnalités qui les rendent non réguliers au sens théorique.^\(\(hede\)\@!.\)*$
Notez que la solution de ne commence pas par «hede» :
est généralement beaucoup plus efficace que la solution ne contient pas de "hede" :
Le premier vérifie «hede» uniquement à la première position de la chaîne d'entrée, plutôt qu'à chaque position.
la source
(.*)(?<!hede)$
. La version de @Nyerguds fonctionnerait également, mais manque complètement le point sur les performances mentionné dans la réponse.^((?!hede).)*$
? N'est-ce pas plus efficace à utiliser^(?!.*hede).*$
? Il fait la même chose mais en moins d'étapesSi vous ne l'utilisez que pour grep, vous pouvez utiliser
grep -v hede
pour obtenir toutes les lignes qui ne contiennent pas de hede.ETA Oh, en relisant la question,
grep -v
c'est probablement ce que vous vouliez dire par "options d'outils".la source
grep -v -e hede -e hihi -e ...
grep -v "hede\|hihi"
:)grep -vf pattern_file file
egrep
ougrep -Ev "hede|hihi|etc"
pour éviter la fuite maladroite.Réponse:
Explication:
^
le début de la chaîne, le(
groupe et la capture à \ 1 (0 fois ou plus (correspondant au plus grand nombre possible)),(?!
regardez en avant pour voir s'il n'y en a pas,hede
votre chaîne,)
fin d'anticipation,.
tout caractère sauf \ n,)*
fin de \ 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 un \ n facultatif, et la fin de la chaînela source
^((?!DSAU_PW8882WEB2|DSAU_PW8884WEB2|DSAU_PW8884WEB).)*$
'Les réponses données sont parfaitement bien, juste un point académique:
Les expressions régulières au sens de l'informatique théorique NE SONT PAS CAPABLES de le faire comme ça. Pour eux, cela devait ressembler à ceci:
Cela ne fait qu'une correspondance COMPLÈTE. Le faire pour les sous-matchs serait encore plus gênant.
la source
(hede|Hihi)
"? (C'est peut-être une question pour CS.)Si vous souhaitez que le test d'expression rationnelle échoue uniquement si la chaîne entière correspond, les éléments suivants fonctionneront:
par exemple - Si vous souhaitez autoriser toutes les valeurs sauf "foo" (c'est-à-dire "foofoo", "barfoo" et "foobar" passeront, mais "foo" échouera), utilisez:
^(?!foo$).*
Bien sûr, si vous vérifiez l' égalité exacte , une meilleure solution générale dans ce cas est de vérifier l'égalité des chaînes, c'est-à-dire
Vous pouvez même mettre la négation en dehors du test si vous avez besoin de fonctionnalités d'expression régulière (ici, insensibilité à la casse et correspondance de plage):
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).
la source
" hede "
?\s
directive correspond à un seul caractère d'espace blanc^(?!\s*hede\s*$).*
FWIW, puisque les langages réguliers (aka langages rationnels) sont fermés par complémentation, il est toujours possible de trouver une expression régulière (aka 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 par le
{c}
suffixe).Vous définissez d' abord le type de vos expressions: les étiquettes sont lettre (
lal_char
) à choisira
àz
par exemple (définir l'alphabet lorsque vous travaillez avec complémentation est, bien sûr, 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:
puis vous entrez votre expression:
convertissez cette expression en automate:
enfin, reconvertissez cet automate en une expression simple.
où
+
est généralement indiqué|
,\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 essayer Vcsn en ligne là-bas .
la source
|
ne joueront pas bien.'^(()|h(ed?)?|([^h]|h([^e]|e([^d]|d([^e]|e.)))).*)$'
.Voici une bonne explication de la raison pour laquelle il n'est pas facile de nier une expression rationnelle arbitraire. Je dois cependant être d'accord avec les autres réponses: s'il ne s'agit pas d'une question hypothétique, alors l'expression rationnelle n'est pas le bon choix ici.
la source
Avec l'anticipation 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. Grande explication!
Cependant, avec la réponse de Bart Kiers, la partie d'anticipation testera 1 à 4 caractères à l'avance tout en faisant correspondre n'importe quel caractère. Nous pouvons éviter cela et laisser la partie d'anticipation vérifier tout le texte, s'assurer qu'il n'y a pas de «haie», puis la partie normale (. *) Peut manger tout le texte en une seule fois.
Voici l'expression rationnelle améliorée:
Notez que le quantificateur paresseux (*?) Dans la partie d'anticipation négative est facultatif, vous pouvez utiliser le quantificateur gourmand (*) à la place, en fonction de vos données: si 'hede' est présent et dans la moitié du 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 également lents.
Voici le code de démonstration .
Pour plus d'informations sur Lookahead, veuillez consulter le grand article: Maîtriser Lookahead et Lookbehind .
Consultez également 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 d'une manière plus lisible:
la source
^(?!.*(str1|str2)).*$
^(?!.*?(?:str1|str2)).*$
selon vos données. Ajout du?:
car nous n'avons pas besoin de le capturer.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. Analyse comparative 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!
Résultats:
Les résultats sont des itérations par seconde comme la médiane de 3 courses - Plus grand nombre = meilleur
Étant donné que .NET ne prend pas en charge les verbes d'action (* FAIL, etc.), je n'ai pas pu tester les solutions P1 et P2.
Sommaire:
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 développée pour
^(?>[^R]+|R+(?!egex Hero))*$
entraîner un petit gain de performances.Mais la solution globale la plus lisible et la plus rapide en termes de performances semble être 05 en utilisant une instruction conditionnelle ou 04 avec le quantificateur possessif. Je pense que les solutions Perl devraient être encore plus rapides et plus lisibles.
la source
^(?!.*hede)
aussi chronométrer . /// En outre, il est probablement préférable de classer séparément les expressions du corpus correspondant et du corpus non correspondant, car c'est généralement le cas que la plupart des lignes correspondent ou que la plupart des lignes ne le font pas.Pas regex, mais je l'ai trouvé logique et utile d'utiliser des greps série avec un tuyau pour éliminer le bruit.
par exemple. rechercher un fichier de configuration apache sans tous les commentaires-
et
La logique du grep série est (pas un commentaire) et (correspond à dir)
la source
grep -v
good_stuff #comment_stuff
avec cela, vous évitez de tester une anticipation sur chaque position:
équivalent à (pour .net):
Ancienne réponse:
la source
/^[^h]*(?:h+(?!ede)[^h]*)*$/
Ce qui précède
(?:(?!hede).)*
est génial car il peut être ancré.Mais ce qui suit suffirait dans ce cas:
Cette simplification est prête à ajouter des clauses "ET":
la source
Voici comment je le ferais:
Précis et plus efficace que les autres réponses. Il met en œuvre la technique d'efficacité "déroulant la boucle" de Friedl et nécessite beaucoup moins de retour en arrière.
la source
Si vous voulez faire correspondre un caractère pour nier un mot similaire à nier la classe de caractères:
Par exemple, une chaîne:
Ne pas utiliser:
Utilisation:
L'avis
"(?!bbb)."
n'est ni lookbehind ni lookahead, c'est lookcurrent, par exemple:la source
(?!
). Le préfixe lookahead positif serait alors(?=
que les préfixes lookbehind correspondants seraient(?<!
et(?<=
respectivement. Une anticipation signifie que vous lisez les caractères suivants (donc «en avance») sans les consommer. Un lookbehind signifie que vous vérifiez les personnages qui ont déjà été consommés.Une variante, à mon avis, plus lisible de la réponse du haut:
Fondamentalement, "correspond au début de la ligne si et seulement si elle ne contient pas" hede "" - donc l'exigence s'est traduite presque directement en expression régulière.
Bien sûr, il est possible d'avoir plusieurs exigences de défaillance:
Détails: l' ancre ^ garantit que le moteur d'expression régulière ne réessaye pas la correspondance à chaque emplacement de la chaîne, ce qui correspondrait à chaque chaîne.
L'ancre ^ au début est censée représenter le début de la ligne. L'outil grep correspond à chaque ligne une par une, dans les contextes où vous travaillez avec une chaîne multiligne, vous pouvez utiliser l'indicateur "m":
ou
la source
L'OP n'a pas précisé ni Tagle post pour indiquer le contexte (langage de programmation, éditeur, outil) dans lequel Regex sera utilisé.
Pour moi, je dois parfois le faire lors de l'édition d'un fichier à l'aide de
Textpad
.Textpad
prend en charge certains Regex, mais ne prend pas en charge lookahead ou lookbehind, donc cela prend quelques étapes.Si je cherche à conserver toutes les lignes qui NE contiennent PAS la chaîne
hede
, je le ferais comme ceci:Vous avez maintenant le texte d'origine avec toutes les lignes contenant la chaîne
hede
supprimées.Si je cherche à faire quelque chose d'autre uniquement aux lignes qui ne contiennent pas la chaîne
hede
, je le ferais comme ceci:la source
Puisque personne d'autre n'a donné de réponse directe à la question qui a été posée , je vais le faire.
La réponse est qu'avec POSIX
grep
, il est impossible de satisfaire littéralement cette demande:La raison en est que POSIX
grep
n'est requis que pour travailler 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'analyser les langues normales, en raison du manque d'alternance et de parenthèses).Cependant, GNU
grep
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\(
et\)
sont les parenthèses. Si votre moteur d'expression régulière prend en charge l'alternance, les expressions de parenthèses négatives, les parenthèses et l'étoile Kleene, et est capable d'ancrer au début et à la fin de la chaîne, c'est tout ce dont vous avez besoin pour cette approche. Notez cependant que les jeux négatifs[^ ... ]
sont très pratiques en plus de ceux-ci, car sinon, vous devez les remplacer par une expression de la forme(a|b|c| ... )
qui répertorie tous les caractères qui ne sont pas dans le jeu, ce qui est extrêmement fastidieux et trop long, d'autant plus si l'ensemble des caractères est Unicode.Avec GNU
grep
, la réponse serait quelque chose comme:(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:Voici un script pour le tester (notez qu'il génère un fichier
testinput.txt
dans le répertoire courant):Dans mon système, il imprime:
comme prévu.
Pour ceux qui s'intéressent aux détails, la technique utilisée consiste à convertir l'expression régulière correspondant au mot en un automate fini, puis à inverser l'automate en changeant chaque état d'acceptation en non-acceptation et vice versa, puis en reconvertissant l'AF résultante 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 l'anticipation négative, cela simplifie beaucoup la tâche. Par exemple, avec GNU grep:
Mise à jour: J'ai récemment trouvé l'excellente bibliothèque FormalTheory de Kendall Hopkins , écrite en PHP, qui fournit une fonctionnalité similaire à Grail. En l'utilisant, et un simplificateur écrit par moi-même, j'ai pu écrire un générateur en ligne d'expressions régulières négatives avec une phrase d'entrée (seuls les caractères alphanumériques et spatiaux sont actuellement pris en charge): http://www.formauri.es/personal/ pgimeno / misc / non-match-regex /
Car
hede
il délivre:qui est équivalent à ce qui précède.
la source
Depuis l'introduction de ruby-2.4.1, nous pouvons utiliser le nouvel opérateur absent dans les expressions régulières de Ruby
du doc officiel
Ainsi, dans votre cas,
^(?~hede)$
fait le travail pour vousla source
Par le verbe PCRE
(*SKIP)(*F)
Cela 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 le regex ci-dessus en le divisant en deux parties.
Partie devant le
|
symbole. La pièce ne doit pas correspondre .Partie après le
|
symbole. La pièce doit être appariée .PARTIE 1
Le moteur Regex commencera son exécution à partir de la première partie.
Explication:
^
Affirme que nous sommes au début.hede
Correspond à la chaînehede
$
Affirme que nous sommes à la fin de la ligne.Ainsi, la ligne qui contient la chaîne
hede
serait mise en correspondance. Une fois que le moteur d'expression régulière voit le verbe suivant(*SKIP)(*F)
( Remarque: vous pourriez écrire(*F)
comme(*FAIL)
), il saute et fait échouer la correspondance.|
appelé altération ou opérateur OU logique ajouté à côté du verbe PCRE qui correspond à son tour toutes les frontières existent entre chaque caractère sur toutes les lignes sauf que la ligne contient la chaîne exactehede
. Voir la démo ici . Autrement dit, il essaie de faire correspondre les caractères de la chaîne restante. Maintenant, l'expression régulière dans la deuxième partie serait exécutée.PARTIE 2
Explication:
^
Affirme que nous sommes au début. c'est-à-dire qu'il correspond à tous les départs de ligne, sauf celui de lahede
ligne. Voir la démo ici ..*
En mode multiligne,.
correspondrait à n'importe quel caractère à l'exception des caractères de retour à la ligne ou de retour chariot. Et*
répéterait le caractère précédent zéro ou plusieurs fois. Il en.*
serait de même pour toute la ligne. Voir la démo ici .Hey pourquoi vous avez ajouté. * Au lieu de. +?
Parce
.*
que correspondrait à une ligne vide mais.+
ne correspondra pas à un blanc. Nous voulons faire correspondre toutes les lignes saufhede
, il peut y avoir une possibilité de lignes vides également dans l'entrée. vous devez donc utiliser.*
au lieu de.+
..+
répéterait le caractère précédent une ou plusieurs fois. Voir.*
correspond à une ligne vide ici .$
L'ancrage de fin de ligne n'est pas nécessaire ici.la source
Il peut être plus facile à gérer pour deux expressions régulières dans votre code, une pour effectuer la première correspondance, puis si elle correspond, exécutez la deuxième expression régulière pour vérifier les cas aberrants que vous souhaitez bloquer par exemple,
^.*(hede).*
puis disposez d'une logique appropriée dans votre code.OK, j'admets que ce n'est pas vraiment une réponse à la question publiée et qu'il peut également utiliser un peu plus de traitement qu'une seule expression régulière. Mais pour les développeurs qui sont venus ici à la recherche d'une solution d'urgence rapide pour un cas aberrant, cette solution ne doit pas être négligée.
la source
Une autre option est que pour ajouter une anticipation positive et vérifier si se
hehe
trouve n'importe où dans la ligne d'entrée, nous annulerions cela, avec une expression similaire à:avec des limites de mots.
L'expression est expliquée dans le panneau supérieur droit de regex101.com , si vous souhaitez l'explorer / la simplifier / la modifier, et dans ce lien , vous pouvez voir comment elle correspondrait à certains exemples d'entrées, si vous le souhaitez.
Circuit RegEx
jex.im visualise les expressions régulières:
la source
Le langage TXR prend en charge la négation des expressions rationnelles.
Un exemple plus compliqué: faites correspondre toutes les lignes commençant par
a
et finissant parz
, mais ne contenant pas la sous-chaînehede
:La négation d'expression régulière n'est pas particulièrement utile en soi, mais lorsque vous avez également une intersection, les choses deviennent intéressantes, car vous avez un ensemble complet d'opérations d'ensemble booléennes: vous pouvez exprimer "l'ensemble qui correspond à ceci, sauf pour les choses qui correspondent à cela".
la source
La fonction ci-dessous vous aidera à obtenir la sortie souhaitée
la source
^ ((?! hede).) * $ est une solution élégante, sauf qu'il consomme des caractères que vous ne pourrez pas 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 consommera pas de caractères:
^ (?!. \ bhede \ b) (? =. \ bhaha \ b)
la source
Comment utiliser les verbes de contrôle de retour arrière de PCRE pour faire correspondre une ligne ne contenant pas de mot
Voici une méthode que je n'ai jamais vue utilisée auparavant:
Comment ça fonctionne
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 d'échec, mais également de ne pas tenter de correspondance supplémentaire 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", la deuxième alternative, un sous-modèle vide, correspond avec succès à la chaîne du sujet.
Cette méthode n'est pas plus efficace qu'un lookahead négatif, mais j'ai pensé que je la mettrais ici au cas où quelqu'un la trouverait astucieuse et trouverait une utilisation pour d'autres applications plus intéressantes.
la source
Une solution plus simple consiste à utiliser l'opérateur not !
Votre instruction if devra correspondre à "contient" et non à "exclut".
Je pense que les concepteurs de RegEx ont prévu de ne pas utiliser d'opérateurs.
la source
Peut-être le trouverez-vous sur Google en essayant d'écrire une expression régulière capable de faire correspondre des segments d'une ligne (par opposition à des lignes entières) qui ne contiennent pas de sous-chaîne. M'a pris un certain 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
<span>
balises 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:
Démo en Ruby:
la source
Avec ConyEdit , vous pouvez utiliser la ligne de commande
cc.gl !/hede/
pour obtenir des lignes qui ne contiennent pas la correspondance regex, ou utiliser la ligne de commandecc.dl /hede/
pour supprimer les lignes qui contiennent la correspondance regex. Ils ont le même résultat.la source
Je voulais ajouter un autre exemple si vous essayez de faire correspondre une ligne entière qui contient la chaîne X , mais ne contient pas aussi chaîne Y .
Par exemple, disons que nous voulons vérifier si notre URL / chaîne contient des " gâteries savoureuses ", tant qu'elle ne contient pas de " chocolat " nulle part.
Ce modèle d'expression régulière fonctionnerait (fonctionne également en JavaScript)
(drapeaux globaux, multilignes dans l'exemple)
Exemple interactif: https://regexr.com/53gv4
Allumettes
(Ces URL contiennent des "gâteries savoureuses" et ne contiennent pas non plus de "chocolat")
Ne correspond pas
(Ces URL contiennent du "chocolat" quelque part - donc elles ne correspondent pas même si elles contiennent des "gâteries savoureuses")
la source