如何否定正则表达式中的特定单词?

时间:2009-08-06 17:20:46

标签: regex

我知道我可以在[^bar]中否定一组字符,但我需要一个正则表达式,其中否定适用于特定的单词 - 所以在我的例子中我如何否定实际的"bar"而不是"any chars in bar"

12 个答案:

答案 0 :(得分:601)

执行此操作的一个好方法是使用negative lookahead

^(?!.*bar).*$
  

负前瞻构造是一对括号,左括号后跟一个问号和一个感叹号。在前瞻内部[是任何正则表达式模式]。

答案 1 :(得分:59)

除非性能最受关注,否则通过第二遍传递结果通常更容易,跳过那些与您想要否定的词匹配的结果。

正则表达式通常意味着您正在编写脚本或某种低性能任务,因此找到一个易于阅读,易于理解且易于维护的解决方案。

答案 2 :(得分:44)

以下正则表达式会做你想要的(只要支持负面的后视和前瞻),正确匹配;唯一的问题是它匹配单个字符(即每个匹配是一个字符而不是两个连续“bar”之间的所有字符),如果你使用非常长的字符串,可能会导致高额开销。

b(?!ar)|(?<!b)a|a(?!r)|(?<!ba)r|[^bar]

答案 3 :(得分:42)

您可以使用negative look-ahead or look-behind

^(?!.*?bar).*
^(.(?<!bar))*?$

或者只使用基础知识:

^(?:[^b]+|b(?:$|[^a]|a(?:$|[^r])))*$

这些都匹配任何不包含bar的内容。

答案 4 :(得分:29)

我在尝试识别以下英语声明的正则表达式时遇到了这个论坛帖子:

  

给定一个输入字符串,匹配所有内容 ,除非此输入字符串恰好是'bar';例如,我想匹配'barrier'和'disbar'以及'foo'。

这是我提出的正则表达式

^(bar.+|(?!bar).*)$

正则表达式的英文翻译是“匹配字符串,如果它以'bar'开头,并且它至少有一个其他字符,或者字符串不以'bar'开头。

答案 5 :(得分:28)

<强>解决方案:

^(?!.*STRING1|.*STRING2|.*STRING3).*$

xxxxxx 确定

xxxSTRING1xxx KO(是否需要)

xxxSTRING2xxx KO(是否需要)

xxxSTRING3xxx KO(是否需要)

答案 6 :(得分:8)

接受的答案很好,但实际上是在正则表达式中缺少一个简单的子表达式否定运算符。这就是grep --invert-match退出的原因。因此,在* nixes中,您可以使用管道和第二个正则表达式来完成所需的结果。

grep 'something I want' | grep --invert-match 'but not these ones'

仍然是一种解决方法,但也许更容易记住。

答案 7 :(得分:3)

我希望补充已接受的答案,并以我最近的答案为讨论作出贡献。

@ChrisVanOpstal分享了this regex tutorial,这是学习正则表达式的绝佳资源。

然而,阅读通常非常耗时。

我制作了一张便于记忆的备忘单。

此引用基于每个班级的大括号[](){},我觉得很容易回忆。

Regex = {
 'single_character': ['[]', '.', {'negate':'^'}],
 'capturing_group' : ['()', '|', '\\', 'backreferences and named group'],
 'repetition'      : ['{}', '*', '+', '?', 'greedy v.s. lazy'],
 'anchor'          : ['^', '\b', '$'],
 'non_printable'   : ['\n', '\t', '\r', '\f', '\v'],
 'shorthand'       : ['\d', '\w', '\s'],
 }

答案 8 :(得分:1)

想到可以做的其他事情。这与我的第一个答案非常不同,因为它不使用正则表达式,所以我决定做第二个答案。

使用您选择的语言split()方法等效于字符串,并将单词取消作为拆分内容的参数。使用Python的一个例子:

>>> text = 'barbarasdbarbar 1234egb ar bar32 sdfbaraadf'
>>> text.split('bar')
['', '', 'asd', '', ' 1234egb ar ', '32 sdf', 'aadf']

这样做的好处,至少在Python中是这样的(我不记得功能在Visual Basic或Java中是否相同)是它让你间接地知道“bar”由于“bar”之间的空字符串包含在结果列表中(尽管开头的空字符串是由于字符串开头有“bar”),因此在字符串中重复了这一点。如果您不想这样,您只需从列表中删除空字符串即可。

答案 9 :(得分:1)

我有一个文件名列表,我想用这种行为(Ruby)排除某些文件名:

files = [
  'mydir/states.rb',      # don't match these
  'countries.rb',
  'mydir/states_bkp.rb',  # match these
  'mydir/city_states.rb' 
]
excluded = ['states', 'countries']

# set my_rgx here

result = WankyAPI.filter(files, my_rgx)  # I didn't write WankyAPI...
assert result == ['mydir/city_states.rb', 'mydir/states_bkp.rb']

这是我的解决方案:

excluded_rgx = excluded.map{|e| e+'\.'}.join('|')
my_rgx = /(^|\/)((?!#{excluded_rgx})[^\.\/]*)\.rb$/

我对此应用程序的假设:

  • 要排除的字符串位于输入的开头,或紧跟斜线后。
  • 允许的字符串以.rb结尾。
  • 允许的文件名在.之前没有.rb个字符。

答案 10 :(得分:0)

this comment提取到bkDJ

class MyFormSerializer(serializers.ModelSerializer):
    class Meta:
        model = MyForm
        fields = (..., 'animals')

    animals = CustomMultipleChoiceField(choices=ANIMAL)

此解决方案的一个不错的特性是可以明确否定(排除)多个单词:

^(?!bar$).*

答案 11 :(得分:0)

如果您确实不想匹配bar这是一个单词,则:

^(?!.*\bbar\b).*$

以上内容将匹配单词边界上不包含bar的任何字符串,也就是说,与非单词字符分开的字符串。但是,除非使用正确的正则表达式标志,否则以上模式中使用的句点/点(.)将不匹配换行符:

^(?s)(?!.*\bbar\b).*$

或者:

^(?!.*\bbar\b)[\s\S]*$

我们正在寻找不是空格还是非空格的任何字符,而不是使用任何特殊标志。那应该覆盖所有字符。

但是,如果我们想匹配可能包含bar而不是特定单词bar的单词怎么办?

(?!\bbar\b)\b\[A-Za-z-]*bar[a-z-]*\b
  1. (?!\bbar\b)断言下一个输入不是bar在单词边界上。
  2. \b\[A-Za-z-]*bar[a-z-]*\b匹配包含bar的单词边界上的任何单词。

See Regex Demo