正则表达式中的异或

Posted

技术标签:

【中文标题】正则表达式中的异或【英文标题】:Exclusive Or in Regular Expression 【发布时间】:2010-09-19 19:36:00 【问题描述】:

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

如果我做类似...

/((foo)|(bar))/

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

谢谢!

【问题讨论】:

foofoobar 是否会匹配,因为它包含“foo”和“foobar”? “丰吧”怎么样?你能提供匹配和不匹配的例子吗? 匹配:“foo”,“bar”不匹配:“foofoo”“barfoo”“foobarfoo”“barbar”“barfoofoo” 如果您不希望 "foofoo" 匹配,那么您实际上并不是在谈论排他性或。 【参考方案1】:

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

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

【讨论】:

确实,我很确定我会将 XOR 逻辑放入代码本身,而不是放在正则表达式中。 如果你的语言有 XOR 运算符,甚至更好,/foo/ xor /bar/。 (Perl 可以。) @Ralf 这不是一个表达式,它是两个用逻辑或运算符连接的表达式。【参考方案2】:

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

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

【讨论】:

【参考方案3】:

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

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

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

【讨论】:

【参考方案4】:

我尝试使用 Regex Coach 来对抗:

x foo y
x bar y
x foobar y

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

\b(foo|bar)\b

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

【讨论】:

【参考方案5】:
\b(foo)\b|\b(bar)\b

并且只使用第一个capture group。

【讨论】:

【参考方案6】:

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

(?(?=regex)then|else)

Regular Expression Conditionals

【讨论】:

【参考方案7】:

如果您的正则表达式语言支持,请使用negative lookaround:

(?<!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

【讨论】:

【参考方案8】:

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

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"  

【讨论】:

【参考方案9】:

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

假设您要匹配仅包含“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
  ...

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

【讨论】:

【参考方案10】:

如果您想要一个真正的排他或,我会在代码中而不是在正则表达式中这样做。在 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)

【讨论】:

【参考方案11】:

这是我用的:

/^(foo|bar)1$/

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

【讨论】:

比公认的答案更优雅的解决方案,尤其是当您有超过 2 个案例时.. 为什么加1,是什么意思? 这是错误的,它只意味着foobar只能匹配一次。 我同意@Karl 这不是异或。它只检查整个字符串是“foo”还是“bar” 你不需要1,因为这表明它应该重复1次。拥有/^(foo|bar)$/ 就足够了。这个正则表达式起作用的原因是你使用了^$;它与重复无关。【参考方案12】:

这将使用 '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

【讨论】:

【参考方案13】:

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

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

【讨论】:

以上是关于正则表达式中的异或的主要内容,如果未能解决你的问题,请参考以下文章

String类 ~正则表达式

模型数据库中的异构类型

正则表达式有两个主要组。两个分组在一个主要组中。同一组级别订单不计算在哪里

正则表达式没有想象中的那么难

正则表达式在js中的用法

c# 正则表达式提取()中的值