33

寻找一些正则表达式帮助。我想设计一个表达式来匹配带有“ foo ”或“ bar ”的字符串,但不能同时匹配“ foo ”和“ bar

如果我做类似...

/((foo)|(bar))/

它将匹配“ foobar ”。不是我要找的。那么,如何仅在存在一个术语或另一个术语时才使正则表达式匹配?

谢谢!

4

13 回答 13

40

这就是我使用的:

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

见:http ://www.regular-expressions.info/quickstart.html下重复

于 2011-12-02T19:57:57.510 回答
20

如果您的正则表达式语言支持它,请使用否定环视

(?<!foo|bar)(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
于 2008-10-29T16:32:06.000 回答
10

您可以使用单个正则表达式来执行此操作,但为了便于阅读,我建议您执行类似...

(/foo/ and not /bar/) || (/bar/ and not /foo/)
于 2008-10-29T15:11:08.923 回答
7

这将需要 '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
于 2014-09-09T10:46:41.427 回答
3

除了“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
  ...
}

如果允许同一目标的多次重复(即“野蛮人”匹配),则可以使用相同的通用方法,然后遍历匹配列表以查看匹配是否都是相同文本的重复,或者是否其他选项也存在。

于 2008-10-29T16:59:24.430 回答
2

您可能要考虑 ? 条件测试。

(?(?=regex)then|else)

正则表达式条件

于 2008-10-29T15:56:11.733 回答
2

如果你想要一个真正的独占或者,我会在代码中而不是在正则表达式中这样做。在 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)
于 2008-10-29T17:59:56.477 回答
1

我知道这是一个迟到的条目,但只是为了帮助其他可能正在寻找的人:

(/b(?:(?:(?!foo)bar)|(?:(?!bar)foo))/b)
于 2015-07-06T03:19:58.313 回答
0

我会用这样的东西。它只是检查单词周围的空格,但如果你使用 . ,你可以使用\bor\B来检查边框\w。这将匹配“foo”或“bar”,所以显然你也必须替换空格,以防万一。(假设您要更换任何东西。)

/\s((foo)|(bar))\s/
于 2008-10-29T15:15:55.717 回答
0

我认为这不能用一个正则表达式来完成。边界可能会或可能不会起作用,具体取决于您匹配的内容。

我会分别匹配每个正则表达式,并对结果进行异或。

foo = re.search("foo", str) != None
bar = re.search("bar", str) != None
if foo ^ bar:
    # do someting...
于 2008-10-29T15:23:32.067 回答
0

我尝试与 Regex Coach 对抗:

x foo y
x bar y
x foobar y

如果我检查该g选项,它确实匹配所有三个单词,因为它在每次匹配后再次搜索。
如果您不想要这种行为,您可以锚定表达式,例如仅在单词边界上匹配:

\b(foo|bar)\b

提供更多关于问题的背景信息(数据是什么样的)可能会给出更好的答案。

于 2008-10-29T15:27:36.690 回答
0
\b(foo)\b|\b(bar)\b

并且只使用第一个捕获组

于 2008-10-29T15:41:23.433 回答
0

使用单词边界,您可以获得单个单词...

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"  
于 2008-10-29T16:44:27.910 回答