Wyrażenie regularne pasujące do podciągu, po którym nie następuje określony inny podciąg

116

Potrzebuję wyrażenia regularnego, które będzie pasować, blahfooblahale nieblahfoobarblah

Chcę, żeby pasowało tylko do foo i wszystkiego dookoła foo, o ile nie następuje po nim bar.

Próbowałem użyć tego: foo.*(?<!bar)co jest dość bliskie, ale pasuje blahfoobarblah. Negatywne spojrzenie z tyłu musi pasować do wszystkiego, a nie tylko do paska.

Specyficznym językiem, którego używam, jest Clojure, który używa wyrażeń regularnych Java pod maską.

EDYCJA: Dokładniej, potrzebuję tego, blahfooblahfoobarblahale nie blahfoobarblahblah.

Rayne
źródło
1
Czy próbowałeś użyć foo. * (? <! Bar. *)?
Thibault Falise

Odpowiedzi:

158

Próbować:

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

Testy:

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

Wyjaśnienie wyrażeń regularnych

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

Inne wyrażenie regularne

Jeśli chcesz wykluczyć tylko barwtedy, gdy jest bezpośrednio po foo, możesz użyć

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

Edytować

Zaktualizowałeś swoje pytanie, aby było bardziej szczegółowe.

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

Nowe testy

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

Nowe wyjaśnienie

(?=.*foo(?!bar))zapewnia, że foozostanie znaleziony, ale nie następuje bezpośredniobar

maček
źródło
To bardzo blisko i bardzo dobra odpowiedź. Wiedziałem, że nie będę wystarczająco szczegółowy. :( Potrzebuję tego: "blahfoomeowwoof / foobar /", aby przejść z powodu samotnego "foo", ale nie tego blahfoobarmeowwoof Jeśli to możliwe.
Rayne
Na marginesie, jak można by dopasować coś takiego jak „bot”, ale nie „botki”?
Rayne
Tak. Mogę użyć tego, co mam teraz, ale byłoby łatwiej, gdybym mógł dopasować tylko bota, ale nie botów. Bardzo mi przykro. Nie mam doświadczenia z wyrażeniami regularnymi i obawiam się, że powoli sam odkrywam, czego chcę. : p
Rayne
1
@Rayne, to jest to samo pytanie. W powyższym przykładzie chciałeś dopasować, fooale nie foobar. Aby dopasować, botale nie botters, użyjesz /(?=.*bot(?!ters))^(\w+)$/.
maček
Cóż, ogólnie dążyłem do całych słów. Jak powiedziałem, jestem zdezorientowany, czego naprawdę chcę i co jest naprawdę możliwe. Zrobienie tego w ten sposób zadziała. Dziękuję za czas. :)
Rayne
55

Aby dopasować foonastępujące elementy do czegoś, od czego nie zaczyna bar, spróbuj

foo(?!bar)

Twoja wersja z negatywnym lookbehind jest efektywnie „dopasuj a, foopo którym następuje coś, co nie kończy się na bar”. W .*meczu o wszystko barblah, i (?<!bar)patrzy na lahi sprawdza, czy nie pasuje bar, które nie, więc cały dopasowania wzorca.

stevemegson
źródło
Więc wypróbowałem to dla wyrażenia regularnego, które zostało zaprojektowane tak, aby pasowało do ciągu „czy ty”, o ile nie występuje po nim „powiedz”. Działa, gdy na przykład rozróżnia się między „czy powiedziałeś” a „czy myślisz”, ale samo „czy ty” nie zostaje przechwycone, a powinno. Jakieś sugestie?
soosus
2

Zamiast tego użyj negatywnego spojrzenia w przyszłość:

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

To zadziałało dla mnie, mam nadzieję, że pomoże. Powodzenia!

Audie
źródło
Proste, ale skuteczne wyrażenie regularne, które działa również w przypadku wykluczania powtarzających się ciągów („foofoo”). Idealny!
Jonas Byström
1

Napisałeś komentarz sugerujący, że podoba Ci się dopasowywanie wszystkich słów w ciągu, a nie całego ciągu.

Zamiast mieszać to wszystko w komentarzu, zamieszczam to jako nową odpowiedź.

New Regex

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

Przykładowy tekst

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere alefooisokherebar notfoobarhere andnofuu needfoo

mecze

foowithbar fooevenwithfoobar foohere butfooisokherebar needfoo

maček
źródło
0

Twoja konkretna prośba o dopasowanie może zostać dopasowana przez:

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

To będzie pasować, blahfooblahfoobarblahale nie blahfoobarblahblah.

Problem z regex z foo.*(?<!bar)jest .*po foo. Dopasowuje tyle dowolnych znaków, w tym znaki po bar.

psie
źródło