NodeJS&Glob:任意数量的文件名、文件扩展名和必须由单个字符串排除的文件?

NodeJS&Glob: any number of filenames, filename extensions and files that must be excluded by single string?

以下 glob 表达式选择所有 .pug 文件,除了 index.pug (filddle):

/src/!(index){.pug,.haml,index.haml}

现在假设我们已经设法停止 haml 支持,因此必须从上面的表达式中删除与 haml 相关的所有内容。问题是如何在不彻底改变其结构的情况下减少上述表达式?此条件对于创建简单且同时灵活的 glob 表达式生成算法很重要。

错误的解决方案(.pug 个文件之间没有匹配项):

/src/!(index){.pug}

以下解决方案也不合适,因为将来我们可能会添加新的文件扩展名支持(例如.slim)。要实现它,我们必须从根本上改变生成以下表达式的算法。

/src/!(index).pug

下面的解决方案也是不合适的,因为我们无法从中排除任意文件。如果我们想排除 index.pugabout.slim,而不是 index.slimabout.pug 怎么办?

/src/!(index).+(pug|slim)

换句话说:以上所有解决方案都不可扩展:

  • 必须选择的文件名
  • 必须选择哪些文件的文件扩展名
  • 必须排除具有特定扩展名的文件名。

重要:在这个问题中,我们不考虑文件接收 globglobbygulp.src()等。我们考虑单字符串生成.

另外:如果以上问题无法用一个字符串解决,请写成(with explanation/commentary).

为什么不起作用?

您已经 运行 了解 minimatch 支持的语法特性。 (对于不知道的读者。OP 用于说明的站点使用最小匹配来评估 glob。)你看这样的模式:

{a,b,c}

并了解到它与名字 abc 相匹配。大括号模式包含一系列由逗号分隔的子模式,如果任何子模式匹配,则大括号模式匹配。所以模式的意思是"if the text matches a OR b OR c, then it is a match"。所以你认为

{a,b}

匹配 ab。或者在散文中 "if the text matches a OR b, then it is a match." 更进一步,你认为你可以这样做:

{a}

表示"if it matches a, then it is a match." 等同于只有模式a。在不知道更好的情况下,认为 {a} 是这个意思是合理的。在允许对条件列表进行 or-ing 的编程语言中,您通常可以对仅包含一个元素的列表执行 or-ing 操作。

但是,最小匹配不是这样工作的。 为了使大括号被识别为表示备选选择,它必须至少包含一个逗号。因此表达式 {a} 将与文字输入 {a} 匹配牙套什么的。

解决方法

您可以修改生成大括号模式的代码,以便如果子模式列表只有一个元素,则重复它。要重用您给出的示例,您需要 .pug 两次在大括号中:

/src/!(index){.pug,.pug}

这使得大括号将被解释为表达替代方案而不是按字面解释。通过重复相同的子模式,匹配的文件集不会改变。

另一种解决方案是生成一个始终包含无法匹配任何元素的大括号模式。例如:

/src/!(index){.pug,!(*)}

最后一个元素无法匹配任何内容,因此它不会添加匹配项,但它的存在足以让 minimatch 根据需要解释大括号。


为了提供一些背景知识:最小匹配对大括号的作用称为 "brace expansion"。当你给 minimatch 一个模式 a{b,c}d,然后 在它做任何其他事情之前 ,它把它转换成两个模式:abcacd 然后它如果任一模式匹配,则认为存在匹配。大括号扩展是从 Unix shell 中采用的 minimatch 以及其余的 globbing 语法。 (它的documentation告诉你看man shman bash等)