Ответ 1
Вы можете сделать это с помощью одного регулярного выражения, но я предлагаю для удобства чтения сделать что-то вроде...
(/foo/ and not /bar/) || (/bar/ and not /foo/)
Ищите немного справки по регулярному выражению. Я хотел бы создать выражение, которое соответствует строке с "foo" ИЛИ "bar", но не оба "foo" AND "bar"
Если я что-то вроде...
/((foo)|(bar))/
Он будет соответствовать "foobar". Не то, что я ищу. Итак, как я могу сделать регулярное выражение только тогда, когда присутствует один или другой термин?
Спасибо!
Вы можете сделать это с помощью одного регулярного выражения, но я предлагаю для удобства чтения сделать что-то вроде...
(/foo/ and not /bar/) || (/bar/ and not /foo/)
Это то, что я использую:
/^(foo|bar){1}$/
Смотрите: http://www.regular-expressions.info/quickstart.html под повторением
Если ваш язык регулярного выражения поддерживает его, используйте отрицательный поиск:
(?<!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
/^(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
Возможно, вы захотите рассмотреть вопрос? условный тест.
(?(?=regex)then|else)
Вы не указали поведение в отношении контента, отличного от "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
...
}
Если допускается несколько повторений одной и той же цели (т.е. "варварский" ), тогда этот же общий подход можно было бы использовать, перейдя по списку совпадений, чтобы увидеть, совпадают ли все повторы одного и того же текста, или если другой вариант также присутствует.
Если вы хотите истинный эксклюзив или, я бы просто сделал это в коде, а не в регулярном выражении. В 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)
Я бы использовал что-то вроде этого. Он просто проверяет пространство вокруг слов, но вы можете использовать \b
или \b
для проверки границы, если вы используете \w
. Это будет соответствовать "foo" или "bar", поэтому, очевидно, вам также придется заменить пробелы, на всякий случай. (Предполагая, что вы что-то заменяете.)
/\s((foo)|(bar))\s/
Я не думаю, что это можно сделать с помощью одного регулярного выражения. И границы могут работать или не работать в зависимости от того, с чем вы согласны.
Я бы соответствовал каждому регулярному выражению отдельно и делал XOR по результатам.
foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
# do someting...
Я пробовал с Regex Coach против:
x foo y
x bar y
x foobar y
Если я проверяю параметр g
, он действительно соответствует всем трем словам, потому что он снова ищет после каждого матча.
Если вы не хотите этого поведения, вы можете привязать это выражение, например, только для соответствия границам слов:
\b(foo|bar)\b
Предоставление большего контекста проблемы (как выглядят данные) может дать лучшие ответы.
\b(foo)\b|\b(bar)\b
И используйте только первую группу .
Используя границы слова, вы можете получить одно слово...
[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"
Я знаю, что это поздняя запись, но только для того, чтобы помочь другим, кто может выглядеть:
(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)