web-dev-qa-db-fra.com

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 régulière qui corresponde à blahfooblah mais pas à blahfoobarblah

Je veux que cela corresponde à foo et à tout ce qui se passe autour de foo, tant que ce n'est pas suivi de bar.

J'ai essayé d'utiliser ceci: foo.*(?<!bar) qui est assez proche, mais il 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 regex Java sous le capot).

EDIT: Plus spécifiquement, j'en ai aussi besoin pour passer blahfooblahfoobarblah mais pas blahfoobarblahblah.

97
Rayne

Essayer:

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

Tests:

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

Explication de l'expression régulière

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 voulez seulement exclure bar alors que c'est juste après foo, vous pouvez utiliser

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

Modifier

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)) s'assure qu'un foo est trouvé mais n'est pas suivi directement bar

132
maček

Pour faire correspondre un foo à un événement qui ne commence pas par bar, essayez

foo(?!bar)

Votre version avec lookbehind négatif est effectivement "correspond à un foo suivi de quelque chose qui ne se termine pas par bar". Le .* correspond à tous les barblah, et le (?<!bar) revient sur lah et vérifie qu'il ne correspond pas à bar, ce qui n'est pas le cas, donc tout le motif correspond.

48
stevemegson

Utilisez plutôt un regard négatif devant vous:

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

Cela a fonctionné pour moi, espérons que cela aide. Bonne chance!

2
Audie

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

Plutôt que d’écrire tout cela dans un commentaire, je l’affiche comme une nouvelle réponse.

New Regex

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

Exemple de texte

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere etnofuu needsfoo

Allumettes

foowithbar fooevenwithfoobar foohere butfooisokherebar needsfoo

1
maček

Votre demande de correspondance spécifique peut être associée à:

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

Cela correspondra à blahfooblahfoobarblah mais pas à blahfoobarblahblah.

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

0
dawg