正则表达式中的异或

问题描述 投票:0回答:14

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

如果我做类似的事情...

/((foo)|(bar))/

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

谢谢!

regex xor
14个回答
44
投票

这就是我用的:

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

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


20
投票

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

(?<!foo|bar)(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

9
投票

您可以使用单个正则表达式来完成此操作,但我建议为了可读性,您可以这样做......

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

9
投票

这将采用“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
投票

您没有指定除“foo”和“bar”之外的内容的行为,或者在没有另一个的情况下重复其中一个内容的行为。例如,“food”或“barbarian”应该匹配吗?

假设您想要匹配仅包含“foo”或“bar”的一个实例的字符串,但不是同时包含“foo”或“bar”的一个实例,也不是同一实例的多个实例,而不考虑字符串中的其他任何内容(即“food”匹配并且“barbarian”不匹配),那么您可以使用正则表达式返回找到的匹配项数,并且仅当找到一个匹配项时才认为它成功。例如,在 Perl 中:

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

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


2
投票

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

(?(?=regex)then|else)

正则表达式条件


2
投票

如果您想要真正的异或,我只需在代码中而不是在正则表达式中执行此操作。在 Perl 中:

/foo/ xor /bar/

但是你的评论:

匹配:“foo”,“bar”不匹配: “foofoo”“barfoo”“foobarfoo”“barbar” “巴福福”

表示您并不是真正在寻找独占或。你实际上的意思是 “

/foo|bar/
是否恰好匹配一次?”

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

my $ok = ($matches == 1)

1
投票

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

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

0
投票

我会用这样的东西。它只是检查单词周围的空间,但如果您使用

\b
,则可以使用
\B
\w
来检查边框。这将匹配“ foo ”或“ bar ”,因此显然您还必须替换空格,以防万一。 (假设您要更换任何东西。)

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

0
投票

我认为这不能用单个正则表达式来完成。边界可能有效,也可能无效,具体取决于您匹配的对象。

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

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

0
投票

我尝试使用 Regex Coach 来反对:

x foo y
x bar y
x foobar y

如果我检查

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

\b(foo|bar)\b

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


0
投票
\b(foo)\b|\b(bar)\b

并且仅使用第一个捕获组


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"  

0
投票

对于初学者来说,拥有一个好的测试用例会有所帮助:

apple
banana
orange
apple and banana
apple and orange
banana and apple
banana and orange
orange and apple
orange and banana
apple and banana and orange
orange and banana and orange
none of the above
apple and microsoft

https://regex101.com/r/ebpyjX/1

首先,

^(?P<XOR>(?=.*apple)(?!.*banana)|(?!.*apple)(?=.*banana)).*$
直接用作异或,但可能会因为许多子项而变得很长:

一个半,

^(?P<XOR>(?=.*apple)(?!.*banana)(?!.*orange)|(?!.*apple)(?=.*banana)(?!.*orange)|(?!.*apple)(?!.*banana)(?=.*orange)).*$
是三值异或的一个例子:

一个又四分之三

^(?P<XOR>(?!(?P<exclusive>(.*apple|.*banana|.*orange){2,}))(?=.*(?P<fruit>apple|banana|orange)).*$)
可以更好地扩展到更多数量的术语,因为它更有效地对逻辑进行分组:

第二,

(?P<xor_is_or_and_nand>^(?P<nand_apple_banana>(?!(?:(?=.*apple)(?=.*banana))))(?P<apple_or_banana>(?=.*apple|.*banana)).*$)
展示了XOR如何是OR + NAND,即在lisp中这看起来像
(and (or apple banana) (nand apple banana))

最后,

(?P<not_with_xor>^(?P<not_microsoft>(?!.*microsoft))(?P<nand_apple_banana>(?!(?:(?=.*apple)(?=.*banana))))(?P<apple_or_banana>(?=.*apple|.*banana)).*$)
展示了如何确保其他否定与异或查询共存:

© www.soinside.com 2019 - 2024. All rights reserved.