137 votes

Une expression rationnelle pour faire correspondre une sous-chaîne qui n'est pas suivie d'une certaine autre sous-chaîne.

J'ai besoin d'une expression rationnelle qui correspondra à blahfooblah mais pas blahfoobarblah

Je veux qu'il corresponde uniquement à foo et à tout ce qui se trouve autour de foo, tant qu'il n'est pas suivi de bar.

J'ai essayé d'utiliser ceci : foo.*(?<!bar) ce qui est assez proche, mais il correspond à blahfoobarblah . L'aspect négatif de l'arrière doit être assorti à n'importe quoi et pas seulement à un bar.

Le langage spécifique que j'utilise est Clojure, qui utilise des regex Java sous le capot.

EDIT : Plus spécifiquement, j'ai aussi besoin qu'il passe blahfooblahfoobarblah mais pas blahfoobarblahblah .

193voto

maček Points 25640

Essayez :

/(?!.*bar)(?=.*foo)^(\w+)$/

Tests :

blahfooblah            # pass
blahfooblahbarfail     # fail
somethingfoo           # pass
shouldbarfooshouldfail # fail
barfoofail             # fail

Explication des expressions régulières

NODE                     EXPLANATION
--------------------------------------------------------------------------------
  (?!                      look ahead to see if there is not:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    bar                      'bar'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  (?=                      look ahead to see if there is:
--------------------------------------------------------------------------------
    .*                       any character except \n (0 or more times
                             (matching the most amount possible))
--------------------------------------------------------------------------------
    foo                      'foo'
--------------------------------------------------------------------------------
  )                        end of look-ahead
--------------------------------------------------------------------------------
  ^                        the beginning of the string
--------------------------------------------------------------------------------
  (                        group and capture to \1:
--------------------------------------------------------------------------------
    \w+                      word characters (a-z, A-Z, 0-9, _) (1 or
                             more times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  )                        end of \1
--------------------------------------------------------------------------------
  $                        before an optional \n, and the end of the
                           string

Autres expressions rationnelles

Si vous souhaitez uniquement exclure bar lorsqu'il se trouve directement après foo vous pouvez utiliser

/(?!.*foobar)(?=.*foo)^(\w+)$/

Editar

Vous avez mis à jour votre question pour la rendre plus spécifique.

/(?=.*foo(?!bar))^(\w+)$/

Nouveaux tests

fooshouldbarpass               # pass
butnotfoobarfail               # fail
fooshouldpassevenwithfoobar    # pass
nofuuhere                      # fail

Nouvelle explication

(?=.*foo(?!bar)) assure une foo est trouvé mais n'est pas suivi directement bar

61voto

stevemegson Points 6741

Pour faire correspondre un foo suivi de quelque chose qui ne commence pas par bar , essayez

foo(?!bar)

Votre version avec le lookbehind négatif est en fait "correspondre à un foo suivi de quelque chose qui ne se termine pas par bar ". Les .* correspond à l'ensemble de barblah et le (?<!bar) regarde en arrière lah et vérifie qu'il ne correspond pas à bar ce qui n'est pas le cas, de sorte que l'ensemble du motif correspond.

2voto

Audie Points 1259

Utilisez plutôt un regard négatif vers l'avenir :

\s*(?!\w*(bar)\w*)\w*(foo)\w*\s*

Cela a fonctionné pour moi, j'espère que cela vous aidera. J'espère que cela vous aidera.

1voto

maček Points 25640

Vous avez écrit un commentaire suggérant que vous aimeriez que cette fonction corresponde à tous les mots d'une chaîne plutôt qu'à l'ensemble de la chaîne elle-même.

Plutôt que d'écraser tout cela dans un commentaire, je le poste comme une nouvelle réponse.

Nouvelles expressions rationnelles

/(?=\w*foo(?!bar))(\w+)/

Texte modèle

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needsfoo

Correspondances

pour la barre pour la barre même avec la barre pour la barre pour la barre mais pour la barre pour la barre besoin de la barre

0voto

dawg Points 26051

Votre demande d'appariement spécifique peut être satisfaite par :

\w+foo(?!bar)\w+

Cela correspondra à blahfooblahfoobarblah mais pas blahfoobarblahblah .

Le problème avec votre expression rationnelle de foo.*(?<!bar) est le .* après foo . Il correspond à autant de caractères que possible, y compris les caractères après bar .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X