有没有一种方法可以编写一个通配符模式,匹配除了某个文件夹中的所有文件?

3

我需要编写一个文件glob,它将匹配除了某个特定文件夹(例如高级文件夹foo/)中包含的所有文件以外的所有文件。

我得到了以下的glob:

!(foo)/**/*

然而,在Ruby的File.fnmatch中,这个glob似乎无法匹配任何文件(即使设置了FNM_PATHNAMEFNM_DOTMATCHtrue)。
另外,Ruby的glob解释器似乎与JavaScript的行为不同: JavaScript glob解释器可以匹配所有字符串。
Ruby glob解释器不能匹配任何字符串。
2.6.2 :027 > File.fnmatch("!(foo)/**/*", "hello/world.js")
 => false
2.6.2 :028 > File.fnmatch("!(foo)/**/*", "test/some/globs")
 => false
2.6.2 :029 > File.fnmatch("!(foo)/**/*", "foo/bar/something.txt")
 => false

1
我没有看到关于File::fnmatch通配符模式的否定文档。 - engineersmnky
1个回答

3

如果确实需要使用通配符,则可以列出允许的内容,使其等同于否定:

extglob = "{[^f]*,f,f[^o]*,fo,fo[^o]*,foo?*}/**/*"

File.fnmatch(extglob, "hello/world.js", File::FNM_EXTGLOB | File::FNM_PATHNAME)
#=> true

File.fnmatch(extglob, "test/some/globs", File::FNM_EXTGLOB | File::FNM_PATHNAME)
#=> true

File.fnmatch(extglob, "foo/bar/something.txt", File::FNM_EXTGLOB | File::FNM_PATHNAME)
#=> false

File.fnmatch(extglob, "food/bar/something.txt", File::FNM_EXTGLOB | File::FNM_PATHNAME)
#=> true

{[^f]*,f,f[^o]*,fo,fo[^o]*,foo?*}的含义是:

  • 任何不以f开头的字符串
  • 字符串f
  • f开头且第二个字符不是o的字符串
  • 字符串fo
  • fo开头且第三个字符不是o的字符串
  • foo开头且长度至少为2的字符串

更新

如果你的字符串太长了,生成一个否定它的glob表达式会很麻烦,那么为什么不编写一个函数呢?

def extglob_neg str
  str.each_char.with_index.with_object([]) do |(_,i),arr|
    arr << "#{str[0,i]}[^#{str[i]}]*"
    arr << str[0..i]
  end.join(',').prepend('{').concat('?*}')
end

extglob_neg "Food"
#=> "{[^F]*,F,F[^o]*,Fo,Fo[^o]*,Foo,Foo[^d]*,Food?*}"

注意: 我在这个函数中没有实现任何glob转义,因为它似乎有点复杂。不过我可能是错的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接