Регулярное выражение для соответствия подстроке, за которой не следует определенная другая подстрока

Мне нужно регулярное выражение, которое будет соответствовать blahfooblah, но не blahfoobarblah

Я хочу, чтобы он соответствовал только foo и все вокруг foo, если за ним не следует панель.

Я попытался использовать это: foo.*(?<!bar), который довольно близок, но соответствует blahfoobarblah. Отрицательный внешний вид должен соответствовать чему угодно, а не просто бару.

Я использую конкретный язык Clojure, который использует Java regexes под капотом.

EDIT: В частности, мне также нужно передать blahfooblahfoobarblah, но не blahfoobarblahblah.

Ответ 1

Попробуйте:

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

Тесты:

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

Объяснение регулярного выражения

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

Другое регулярное выражение

Если вы хотите исключить bar, когда он находится непосредственно после foo, вы можете использовать

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

Изменить

Вы сделали обновление своего вопроса, чтобы сделать его конкретным.

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

Новые тесты

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

Новое объяснение

(?=.*foo(?!bar)) обеспечивает обнаружение foo, но не выполняется непосредственно bar

Ответ 2

Чтобы соответствовать foo, следуя чему-то, что не начинается с bar, попробуйте

foo(?!bar)

Ваша версия с отрицательным lookbehind эффективно "соответствует foo, за которой следует что-то, что не заканчивается на bar". .* соответствует всем barblah, а (?<!bar) оглядывается на lah и проверяет, что он не соответствует bar, а это не так, поэтому весь шаблон соответствует.

Ответ 3

Вместо этого используйте негативный прогноз:

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

Это сработало для меня, надеюсь, что это поможет. Удачи!

Ответ 4

Ваш конкретный запрос соответствия может быть сопоставлен:

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

Это будет соответствовать blahfooblahfoobarblah, но не blahfoobarblahblah.

Проблема с вашим регулярным выражением foo.*(?<!bar) - это .* после foo. Он соответствует числу любых символов, включая символы после bar.

Ответ 5

Вы написали комментарий, предполагающий, что вам нравится это, чтобы соответствовать всем словам в строке, а не всей самой строке.

Вместо того, чтобы смять все это в комментарии, я отправляю его как новый ответ.

Новое регулярное выражение

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

Пример текста

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar notfoobarhere andnofuu needsfoo

Матчи

foowithbar fooevenwithfoobar foohere butfooisokherebar needsfoo