Web 平台 API / glob · 文件路径的迷你匹配语言 / brace 多选一与 extglob 方言差异 待审核 3 / 6
03 · {} 与 extglob

brace 多选一与 extglob 方言差异

「js 和 ts 都要」有两种写法,机制完全不同:{js,ts} 在 bash 里是 brace expansion——匹配开始之前先把一条 pattern 文本展开成多条;@(js|ts)extglob——匹配进行当中在段内做选择/重复。本仓库实现 @vega/parsing/glob 收录了 {a,b}(转译成 regex 的 (?:a|b),不做文本预展开),未收录 extglob 与 {1..3} 数字区间——后两者在本页只做语法对照,不提供交互 demo。

1 · 花括号的多选一语义

图 1-1 · 花括号展开的对照:左侧列出各分支,右侧是转译后的一条正则,可改 pattern 观察分支如何相乘。

规则三条:逗号分选项 {a,b};可嵌套——jp{,e}g 里那个空选项展开出 jpg / jpeg;可以包住 /——{src/a,test/b}/*.ts 的每个分支都是一条完整的多段 pattern。多个组相邻就是笛卡尔积,条数相乘(最后一个预设 2×2×2 = 8 条)——这也是它的风险:分支数随组数指数增长,在大目录上要克制。

两种实现机制,同一个匹配结果。bash 把 brace 当文本预处理:先展开成 N 条 pattern 再逐条匹配(所以 bash 里 echo {a,b}.txt 不需要任何文件存在也会输出两个名字)。本仓库实现走另一条路:{a,b} 作为 AST 节点直接转译成 regex 的分支 (?:a|b),一条 regex 一次匹配完成——上面第二块输出就是证据。在 {a,b} 这类多选项花括号上,两种机制对「path 是否命中」等价。单选项则不然:bash 的 brace expansion 要求至少两个选项(或一个区间),echo x{a}y 原样输出 x{a}y;而本仓库实现把它译成 (?:a),于是 xay 命中、字面的 x{a}y 反而不命中(实测)。

**{1..3} 数字区间:本仓库实现未收录。**bash 与 minimatch 支持 file{1..5}.txt 这种区间展开(铺成 file1.txtfile5.txt);@vega/parsing/glob 未收录这个语法,{1..5} 会被当成一个单分支的花括号:转译后花括号消失,file{1..5}.txt 实际匹配的是 file1..5.txt,而字面的 file{1..5}.txt 反而不命中(实测)——这条 pattern 既不报错也永远命中不到预期文件。需要同样效果时写显式列表 file{1,2,3,4,5}.txt 或字符类 file[1-5].txt

2 · extglob:段内的带量词分组

bash 系还有一组「分组 + 量词」语法,量词写在分组前面,统称 extglob。它是 bash 的可选特性(需 shopt -s extglob),minimatch / node-glob 默认支持,VS Code 的 glob 与本仓库实现都不支持(核对于 2026-08)。语法对照如下(仅供阅读,本页不提供交互 demo):

图 2-1 · extglob 五种量词的语法对照,仅作阅读,本仓库实现不支持。

最实用的是 !(...) 反选:!(*.min).js 读作「js 文件,但 .js 前面那截不能匹配 *.min」。这条语义在 bash 与 picomatch 上成立(实测两者都把 x.min.js 排除),但 minimatch 10.2.6 判它命中——在 node-glob 里靠它收压缩产物会收不干净(核对于 2026-08)。config?(.local).json 则用 ?() 同时覆盖「带与不带 .local」两种文件名。在不支持 extglob 的环境里,反选要改用工具自身的排除机制(如 node-glob 的 ignore 选项,见 04 页),多选一优先写三家通用的 {}

**支持度差异比语法本身更重要:**extglob 是 bash 系特性,跨工具复用的 pattern 应避开它;{} 在 bash / node-glob / VS Code 都可用(gitignore 不认)。完整对照见 06 速查页