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.


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


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.


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!


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


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.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.