Une expression régulière pour correspondre à une sous-chaîne qui n'est pas suivie d'une certaine autre sous-chaîne

116

J'ai besoin d'une regex qui correspondra blahfooblahmais pasblahfoobarblah

Je veux qu'il ne corresponde qu'à foo et tout autour de foo, tant qu'il n'est pas suivi de bar.

J'ai essayé d'utiliser ceci: ce foo.*(?<!bar)qui est assez proche, mais cela correspond blahfoobarblah. Le regard négatif derrière doit correspondre à tout et pas seulement à la barre.

Le langage spécifique que j'utilise est Clojure qui utilise des expressions régulières Java sous le capot.

EDIT: Plus précisément, j'en ai aussi besoin pour passer blahfooblahfoobarblahmais pas blahfoobarblahblah.

Rayne
la source
1
Avez-vous essayé d'utiliser foo. * (? <! Bar. *)?
Thibault Falise

Réponses:

158

Essayer:

/(?!.*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

Autre regex

Si vous souhaitez exclure uniquement barlorsque c'est juste après foo, vous pouvez utiliser

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

Éditer

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

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

Nouveaux tests

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

Nouvelle explication

(?=.*foo(?!bar))garantit qu'un fooest trouvé mais n'est pas suivi directementbar

maček
la source
C'est très proche et une très bonne réponse. Je savais que je ne serais pas assez précis. :( J'ai besoin de ceci: "blahfoomeowwoof / foobar /" pour passer à cause du solitaire "foo", mais pas de ce blahfoobarmeowwoof Si c'est possible.
Rayne
En guise de question secondaire, comment procéder pour faire correspondre quelque chose comme "bot" mais pas "botters"?
Rayne
Oui. Je peux utiliser ce que j'ai maintenant, mais ce serait plus facile si je pouvais simplement faire correspondre le bot mais pas les botteurs. Je suis vraiment désolé. Je suis inexpérimenté avec les expressions régulières et j'ai peur de comprendre lentement ce que je veux moi-même. : p
Rayne
1
@Rayne, c'est la même question. Dans votre exemple ci-dessus, vous vouliez faire correspondre foomais pas foobar. Pour correspondre botmais pas botters, vous utiliseriez /(?=.*bot(?!ters))^(\w+)$/.
maček
Eh bien, je visais généralement des mots entiers. Comme je l'ai dit, je ne sais pas trop ce que je veux vraiment et ce qui est vraiment possible. Faire comme ça fonctionnera. Merci pour le temps. :)
Rayne
55

Pour faire correspondre une foosuite à quelque chose qui ne commence pas par bar, essayez

foo(?!bar)

Votre version avec un look-back négatif est en fait "match a foosuivi de quelque chose qui ne se termine pas par bar". Le .*correspond à tous barblah, et le (?<!bar)regarde en arrière lahet vérifie qu'il ne correspond pas bar, ce qui n'est pas le cas, donc tout le modèle correspond.

stevemegson
la source
J'ai donc essayé ceci pour une expression régulière conçue pour correspondre à la chaîne "as-tu" tant qu'elle n'est pas suivie de "dire". Cela fonctionne lorsque vous faites la différence entre «avez-vous dit» et «avez-vous pensé», par exemple, mais simplement «avez-vous» en lui-même n'est pas capturé, et il devrait. Aucune suggestion?
soosus
2

Utilisez plutôt une perspective négative:

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

Cela a fonctionné pour moi, j'espère que cela aide. Bonne chance!

Audie
la source
Regex simple mais efficace, qui fonctionne également pour exclure les chaînes répétitives ("foofoo"). Parfait!
Jonas Byström
1

Vous avez écrit un commentaire vous suggérant de faire correspondre tous les mots d'une chaîne plutôt que la chaîne entière elle-même.

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

Nouveau Regex

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

Exemple de texte

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needsfoo

Allumettes

foowithbar fooevenwithfoobar foohere butfooisokherebar needsfoo

maček
la source
0

Votre demande de correspondance spécifique peut être assortie de:

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

Cela correspondra blahfooblahfoobarblahmais pas blahfoobarblahblah.

Le problème avec votre regex de foo.*(?<!bar)est l' .*après foo. Il correspond à autant de caractères, y compris les caractères après bar.

dawg
la source