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


当前回答

我有一个文件名列表,我想通过这种行为(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之前的字符。

其他回答

我想补充已接受的答案,并用我迟来的答案为讨论作出贡献。

@ChrisVanOpstal分享了这个正则表达式教程,这是学习正则表达式的一个很好的资源。

然而,通读起来确实很耗时。

为了便于记忆,我做了一张备忘单。

这个引用基于每个类前面的大括号[]、()和{},我觉得很容易回忆起来。

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'],
 }

您可以使用消极的前瞻性或滞后性:

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

或者只使用基础知识:

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

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

除非性能是最重要的,否则通常只需通过第二次测试来运行结果,跳过那些与您想要否定的单词相匹配的单词就更容易了。

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

摘自bkDJ的评论:

^(?!bar$).*

此解决方案的优点是可以明确否定(排除)多个单词:

^(?!bar$|foo$|banana$).*

解决方案:

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

xxxxxx正常

xxxSTRING1xxx KO(是否需要)

xxxSTRING2xxx KO(是否需要)

xxxSTRING3xxx KO(是否需要)