Регулярное выражение для соответствия подстроки, за которой не следует определенная другая подстрока - PullRequest
96 голосов
/ 13 апреля 2010

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

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

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

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

РЕДАКТИРОВАТЬ: Более конкретно, мне также нужно, чтобы он передавал blahfooblahfoobarblah, но не blahfoobarblahblah.

Ответы [ 5 ]

130 голосов
/ 13 апреля 2010

Попробуйте:

/(?!.*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

46 голосов
/ 13 апреля 2010

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

foo(?!bar)

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

2 голосов
/ 13 апреля 2010

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

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

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

1 голос
/ 13 апреля 2010

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

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

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

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

Образец текста

для бара, даже для обуви, не для бара, для бара и для бара, но для бара, для этого и для нужды

Матчи

для бара, даже для бара, для бара, но для этого нужен бар

0 голосов
/ 13 апреля 2010

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...