Подтвердить что ты не робот

Эксклюзив или в регулярном выражении

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

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

/((foo)|(bar))/

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

Спасибо!

4b9b3361

Ответ 1

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

(/foo/ and not /bar/) || (/bar/ and not /foo/)

Ответ 3

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

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

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

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

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

foo: true
bar: true
foofoo: false
barfoo: false
foobarfoo: false
barbar: false
barfoofoo: false

Ответ 4

/^(foo|bar)$/

возьмет "foo" и "bar", но не "foobar", а не "blafoo", а не "blabar"

/\b(foo|bar)\b/

возьмет "foo" и "bar" и "foo bar" и "bar-foo", но не "foobar", а не "blafoo", а не "blabar"

^ = mark start of string (or line)
$ = mark end of string (or line)
\b = mark word boundry

Ответ 6

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

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

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

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

Ответ 7

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

/foo/ xor /bar/

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

Матчи: "foo", "bar" nonmatches: "foofoo" "barfoo" "foobarfoo" "barbar" "Barfoofoo"

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

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

my $ok = ($matches == 1)

Ответ 8

Я бы использовал что-то вроде этого. Он просто проверяет пространство вокруг слов, но вы можете использовать \b или \b для проверки границы, если вы используете \w. Это будет соответствовать "foo" или "bar", поэтому, очевидно, вам также придется заменить пробелы, на всякий случай. (Предполагая, что вы что-то заменяете.)

/\s((foo)|(bar))\s/

Ответ 9

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

Я бы соответствовал каждому регулярному выражению отдельно и делал XOR по результатам.

foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
    # do someting...

Ответ 10

Я пробовал с Regex Coach против:

x foo y
x bar y
x foobar y

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

\b(foo|bar)\b

Предоставление большего контекста проблемы (как выглядят данные) может дать лучшие ответы.

Ответ 11

\b(foo)\b|\b(bar)\b

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

Ответ 12

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

[email protected] ~  
$ echo "Where is my bar of soap?" | egrep "\bfoo\b|\bbar\b"  
Where is my bar of soap?  

[email protected] ~  
$ echo "What the foo happened here?" | egrep "\bfoo\b|\bbar\b"  
What the foo happened here?  

[email protected] ~  
$ echo "Boy, that sure is foobar\!" | egrep "\bfoo\b|\bbar\b"  

Ответ 13

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

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)