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


116

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

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

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

Конкретный язык, который я использую, - это Clojure, который использует регулярные выражения Java под капотом.

РЕДАКТИРОВАТЬ: Более конкретно, мне тоже нужно пройти, blahfooblahfoobarblahно нет blahfoobarblahblah.


1
Вы пробовали использовать foo. * (? <! Bar. *)?
Тибо Фалис,

Ответы:


158

Пытаться:

/(?!.*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))гарантирует, что a fooнайден, но не отслеживается напрямуюbar


Это очень близко и очень хороший ответ. Я знал, что не буду достаточно конкретным. :( Мне нужно это: "blahfoomeowwoof / foobar /", чтобы передать из-за одинокого "foo", но не этот blahfoomeowwoof, если это возможно.
Rayne

В качестве побочного вопроса, как можно сопоставить что-то вроде «бот», но не «боттеры»?
Rayne

Да. Я могу использовать то, что у меня есть сейчас, но было бы проще, если бы я мог просто сопоставить с ботами, но не с боттерами. Мне очень жаль. У меня нет опыта работы с регулярными выражениями, и, боюсь, я сам медленно выясняю, чего хочу. : p
Rayne

1
@Rayne, это тот же вопрос. В приведенном выше примере вы хотели сопоставить, fooно нет foobar. Чтобы соответствовать, botно не botters, вы должны использовать /(?=.*bot(?!ters))^(\w+)$/.
maček

Ну, я вообще стремился к целым словам. Как я уже сказал, я не понимаю, чего я действительно хочу и что действительно возможно. Это сработает. Спасибо за время. :)
Rayne

55

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

foo(?!bar)

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


Итак, я попробовал это для регулярного выражения, которое разработано для соответствия строке «did you», если за ней не следует «say». Это работает, когда, например, различие между «вы сказали» и «вы думали», но просто «сделал ли вы» само по себе не улавливается, а должно. Какие-либо предложения?
soosus

2

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

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

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


Простое, но эффективное регулярное выражение, которое также работает для исключения повторяющихся строк («foofoo»). Отлично!
Йонас Быстрём

1

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

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

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

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

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

foowithbar fooevenwithfoobar notfoobar foohere notfoobarhere, ноfooisokherebar notfoobarhere andnofuu needfoo

Спички

foowithbar fooevenwithfoobar foohere butfooisokherebar needfoo


0

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

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

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.