Эксклюзив или в регулярном выражении - PullRequest
28 голосов
/ 29 октября 2008

Нужна помощь в регулярных выражениях. Я хотел бы разработать выражение, соответствующее строке с " foo " ИЛИ " bar ", но не оба " foo " И " бар"

Если я сделаю что-то вроде ...

/((foo)|(bar))/

Это будет соответствовать " foobar ". Не то, что я ищу. Итак, как я могу сопоставить регулярное выражение только при наличии одного или другого термина?

Спасибо!

Ответы [ 13 ]

32 голосов
/ 02 декабря 2011

Вот что я использую:

/^(foo|bar){1}$/

См .: http://www.regular -expressions.info / quickstart.html при повторении

16 голосов
/ 29 октября 2008

Если ваш язык регулярных выражений поддерживает это, используйте негативный обзор :

(?<!foo|bar)(foo|bar)(?!foo|bar)

Это будет соответствовать "foo" или "bar", которым не предшествует сразу же или не следует "foo" или "bar", что, я думаю, то, что вы хотели.

Из вашего вопроса или примеров не ясно, может ли строка, которую вы пытаетесь сопоставить, содержать другие токены: "foocuzbar". Если это так, этот шаблон не будет работать.

Вот результаты ваших тестов («истина» означает, что шаблон был найден во входных данных):

foo: true
bar: true
foofoo: false
barfoo: false
foobarfoo: false
barbar: false
barfoofoo: false
9 голосов
/ 29 октября 2008

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

(/foo/ and not /bar/) || (/bar/ and not /foo/)
6 голосов
/ 09 сентября 2014

Это займет «foo» и «bar», но не «foobar», а не «blafoo» и не «blabar»:

/^(foo|bar)$/

^ = mark start of string (or line)
$ = mark end of string (or line)

Это займет «foo», «bar», «foo bar» и «bar-foo», но не «foobar», а не «blafoo» и не «blabar»:

/\b(foo|bar)\b/

\b = mark word boundry
3 голосов
/ 29 октября 2008

Вы не указали поведение в отношении содержимого, отличного от «foo» и «bar», или повторений одного в отсутствие другого. например, " foo d" или " barbar ian" должны совпадать?

Предполагая, что вы хотите сопоставить строки, которые содержат только один экземпляр "foo" или "bar", но не оба и не несколько экземпляров одного и того же, без учета чего-либо еще в строке (т. Е. "Food" «совпадения и« варвар »не совпадает), то вы можете использовать регулярное выражение, которое возвращает количество найденных совпадений и считает его успешным только в случае обнаружения только одного совпадения». например, в Perl:

@matches = ($value =~ /(foo|bar)/g)  # @matches now hold all foos or bars present
if (scalar @matches == 1) {          # exactly one match found
  ...
}

Если разрешено многократное повторение одной и той же цели (т. Е. «Варварские» совпадения), то можно использовать этот же общий подход, а затем пройтись по списку совпадений, чтобы увидеть, все ли совпадения являются повторениями одного и того же текста или, если другая опция также присутствует.

2 голосов
/ 29 октября 2008

Вы можете рассмотреть? условный тест.

(?(?=regex)then|else)

Условные выражения регулярных выражений

1 голос
/ 06 июля 2015

Я знаю, что это поздняя запись, но просто, чтобы помочь другим, которые могут искать:

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)
1 голос
/ 29 октября 2008

Если вы хотите настоящий эксклюзив или, я бы просто сделал это в коде, а не в регулярном выражении. В Perl:

/foo/ xor /bar/

Но ваш комментарий:

Совпадения: "foo", "bar" несовпадения: "foofoo" "barfoo" "foobarfoo" "barbar" "Barfoofoo"

означает, что вы не ищете эксклюзив или. Вы на самом деле имеете в виду «Совпадает ли /foo|bar/ ровно один раз?»

my $matches = 0;
while (/foo|bar/g) {
  last if ++$matches > 1;
}

my $ok = ($matches == 1)
0 голосов
/ 29 октября 2008

Используя границы слова, вы можете получить одно слово ...

me@home ~  
$ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
Where is my bar of soap?  

me@home ~  
$ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
What the foo happened here?  

me@home ~  
$ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  
0 голосов
/ 29 октября 2008
\b(foo)\b|\b(bar)\b

И использовать только первую группу захвата .

...