Comment nier un mot spécifique dans regex?

je sais que je peux nier un groupe de caractères comme dans [^bar] mais j'ai besoin d'une expression régulière où la négation s'applique au mot spécifique - ainsi dans mon exemple comment puis-je nier une réelle "bar" et non "any chars in bar" ?

480
demandé sur robsch 2009-08-06 21:20:45

10 réponses

une bonne façon de le faire est d'utiliser lookahead négatif :

^(?!.*bar).*$
534
répondu Chris Van Opstal 2009-08-06 17:38:49

à moins que la performance ne soit une préoccupation majeure, il est souvent plus facile de passer vos résultats à travers une seconde passe, en sautant ceux qui correspondent aux mots que vous voulez nier.

les expressions régulières signifient généralement que vous faites des scripts ou une sorte de tâche de faible performance de toute façon, alors trouvez une solution qui est facile à lire, facile à comprendre et facile à entretenir.

59
répondu Bryan Oakley 2009-08-06 17:33:13

le regex suivant fera ce que vous voulez (aussi longtemps que les lookbehinds négatifs et les lookheads sont supportés), en faisant correspondre les choses correctement; le seul problème est qu'il correspond à des caractères individuels (c.-à-d. chaque correspondance est un caractère unique plutôt que tous les caractères entre deux"barres" consécutives), résultant peut-être un potentiel de surimpression élevée si vous travaillez avec de très longues chaînes.

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]
40
répondu JAB 2012-06-19 14:39:56

vous pouvez utiliser un regard négatif ou un :

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

ou utilisez juste les bases:

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

ils correspondent à tout ce qui ne contient pas bar .

34
répondu Gumbo 2009-08-06 18:22:45

je suis tombé sur ce fil du forum en essayant d'identifier un regex pour la déclaration suivante en anglais:

avec une chaîne de caractères, faites correspondre tout à moins que cette chaîne de caractères soit exactement "bar"; par exemple, je veux faire correspondre "barrier" et "disbar" ainsi que "foo".

voici le regex que j'ai inventé

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

Mon Anglais la traduction de l'expression régulière est "correspond à la chaîne si elle commence par" bar "et il a au moins un autre personnage, ou si la chaîne ne commence pas par "bar".

24
répondu ReQuest Programmer 2011-10-27 22:32:12

Solution:

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

xxxxxx OK

"

xxxSTRING1xxx KO (est de savoir si cela est souhaité)

xxxSTRING2xxx KO (est de savoir si cela est souhaité)

xxxSTRING3xxx KO (est de savoir si cela est souhaité)

21
répondu sgrillon 2016-09-13 16:24:36

la réponse acceptée est agréable, mais c'est vraiment une solution de rechange pour l'absence d'un simple opérateur de négation de sous-expression dans regexes. C'est pourquoi grep --invert-match sort. Ainsi, en *nixes, vous pouvez accomplir le résultat désiré en utilisant des pipes et un second regex.

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

toujours un contournement, mais peut-être plus facile à se rappeler.

5
répondu Greg Bell 2016-01-04 00:04:46

j'espère compléter la réponse

Comme Chris spécifié Regex Tutoriel est une des meilleures ressources pour l'apprentissage de la regex.

cependant, il a vraiment pris le temps de lire à travers.

je fais un cheatsheet pour le confort mnémotechnique.

[] , () , {} mener chaque classe qui est facile à se rappeler.

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

vient de penser à autre chose qui pourrait être fait. C'est très différent de ma première réponse, car elle n'utilise pas d'expressions régulières, donc j'ai décidé de faire un second message de réponse.

utilisez l'équivalent de la méthode split() de votre choix sur la chaîne avec le mot à nier comme argument pour ce qu'il faut diviser. Un exemple utilisant Python:

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

la bonne chose à faire de cette façon, en Python au moins (je ne me souviens pas si la fonctionnalité serait la même dans, Par exemple, Visual Basic ou Java), c'est qu'elle permet de savoir indirectement quand "bar" a été répété dans la chaîne de caractères en raison du fait que les chaînes vides entre "bar"sont incluses dans la liste des résultats (bien que la chaîne vide au début est due à l'existence d'une "barre" au début de la chaîne de caractères). Si vous ne voulez pas cela, vous pouvez simplement supprimer les chaînes vides de la liste.

1
répondu JAB 2009-08-11 13:12:49

j'avais une liste de noms de fichiers, et je voulais en exclure certains, avec ce genre de comportement (Ruby):

files = [
  'mydir/states.rb',      # don't match these
  'countries.rb',
  'mydir/states_bkp.rb',  # match these
  'mydir/city_states.rb' 
]
excluded = ['states', 'countries']

# set my_rgx here

result = WankyAPI.filter(files, my_rgx)  # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']

voici ma solution:

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

mes hypothèses pour cette application:

  • La chaîne d'exclusion est au début de l'entrée, ou immédiatement après une barre oblique.
  • les cordes autorisées se terminent par .rb .
  • Les noms de fichiers autorisés n'ont pas de caractère . avant .rb .
1
répondu Chaim Leib Halbert 2016-02-25 00:46:02