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"
?
10 réponses
une bonne façon de le faire est d'utiliser lookahead négatif :
^(?!.*bar).*$
à 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.
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]
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
.
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".
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é)
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.
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'],
}
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.
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
.