Регекс для відповідності підрядку, за якою не супроводжується певна інша підрядка


116

Мені потрібен регулярний вираз, який буде відповідати, blahfooblahале ніblahfoobarblah

Я хочу, щоб він відповідав лише футу і все навколо foo, доки за ним не слідує смуга.

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

Мовою, якою я користуюся, є Clojure, яка використовує регекси Java під кришкою.

EDIT: Більш конкретно, мені також це потрібно, щоб пройти, 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))гарантує, що fooзнайдено, але безпосередньо за ним не дотримуєтьсяbar


Це дуже близько, і дуже хороша відповідь. Я знав, що не буду достатньо конкретним. :( Мені потрібно це: "blahfoomeowwoof / foobar /" пройти через самотнє "foo", але не це blahfoobarmeowwoof Якщо це можливо.
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, чого не відповідає, тому весь зразок відповідає.


Тому я спробував це для регулярного вираження, призначеного для відповідності рядку "зробив ти" до тих пір, поки за ним не слідує "сказати". Це працює, коли розрізняють, наприклад, "ти сказав" і "ти думав", але просто "ти" сам по собі не потрапляє в полон, і це повинно. Будь-які пропозиції?
soosus

2

Замість цього скористайтеся негативним поглядом:

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

Це працювало для мене, сподіваюся, що це допомагає. Удачі!


Простий, але ефективний регулярний вираз, який також працює для виключення повторюваних рядків ("foofoo"). Ідеально!
Jonas Byström

1

Ви написали коментар, запропонувавши вам подобатися, щоб це працювало на відповідність усіх слів у рядку, а не на весь рядок.

Замість того, щоб все це робити в коментарі, я публікую це як нову відповідь.

Новий Регекс

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

Зразок тексту

foofithbar fooevenwithfoobar notfoobar foohere notfoobarhere butfooisokherebar 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.