braces

中文文档
3.0.3发布于 2024/05/21MITCommonJS近 30 天下载 6.5亿

类似bash的大括号展开,在JavaScript中实现。比其他大括号扩展库更安全,完全支持Bash 4.3大括号规范,而不牺牲速度。

中文使用文档
文档目录34 节
  1. 安装
  2. v3.0.0发布! !
  3. 为什么要用大括号?
  4. 用法
  5. 大括号展开与编译
  6. 列表
  7. 序列
  8. Steppped范围
  9. 嵌套
  10. 逃离
  11. 选项
  12. options.maxLength
  13. options.expand
  14. options.nodupes
  15. options.rangeLimit
  16. options.transform
  17. options.quantifiers
  18. options.keepEscaping
  19. 什么是“支撑扩张”?
  20. 括号匹配
  21. 支架匹配缺陷
  22. tldr
  23. 解决方案
  24. 几何复杂性
  25. 表演
  26. 更好的算法
  27. 更快的算法
  28. 基准
  29. 运行基准测试
  30. 最新的结果
  31. 关于
  32. 贡献者
  33. 作者
  34. 许可证

牙套 Donate NPM version NPM monthly downloads NPM total downloads Linux Build Status

类似bash的大括号展开,在JavaScript中实现。比其他大括号扩展库更安全,完全支持Bash 4.3大括号规范,而不牺牲速度。

请考虑跟随这个项目的作者, Jon Schlinkert,并考虑主演该项目,以展示您的: 心: 和支持。

安装

安装与 npm:

$ npm install --save braces

v3.0.0发布! !

看到 更新日志 获取详细信息。

为什么要用大括号?

大括号模式通过添加匹配特定范围和字符序列的能力,使globs更加强大。

  • 准确的 -完全支持 Bash 4.3扩展括号 规范(通过所有Bash大括号测试)
  • 快速高效 -开始快,跑得快 良好的可扩展性 随着模式复杂性的增加。
  • 有组织的代码库 解析器和编译器在出现边缘情况时易于维护和更新。
  • 经过良好测试的 -数以千计的测试断言,并通过所有的Bash, minimatch,和 brace-expansion 单元测试(截至撰写本文的日期)。
  • 更安全的 -你不应该担心用户定义攻击性或恶意的大括号模式,这会破坏你的应用程序。brace采取措施防止恶意的regex被用于DDoS攻击(参见 灾难性的回溯).
  • 支持列表 -(又名“集合”) a/{b,c}/d = > ['a/b/d', 'a/c/d']
  • 支持序列 -(又名“ranges”) {01..03} = > ['01', '02', '03']
  • 支持措施 -(又名“增量”) {2..10..2} = > ['2', '4', '6', '8', '10']
  • 支持转义 -防止特殊字符的求值。

用法

主导出是一个接受一个或多个大括号的函数 patterns 和 options。

const braces = require('braces');
// braces(patterns[, options]);

console.log(braces(['{01..05}', '{a..e}']));
//=> ['(0[1-5])', '([a-e])']

console.log(braces(['{01..05}', '{a..e}'], { expand: true }));
//=> ['01', '02', '03', '04', '05', 'a', 'b', 'c', 'd', 'e']

大括号展开与编译

默认情况下,大括号模式被编译成针对创建正则表达式和匹配进行优化的字符串。

编译

console.log(braces('a/{x,y,z}/b'));
//=> ['a/(x|y|z)/b']
console.log(braces(['a/{01..20}/b', 'a/{1..5}/b']));
//=> [ 'a/(0[1-9]|1[0-9]|20)/b', 'a/([1-5])/b' ]

扩大

来启用大括号展开 expand 选项设置为true,或使用 braces.expand () (返回与Bash类似的数组,或者 echo {1..5},或 minimatch):

console.log(braces('a/{x,y,z}/b', { expand: true }));
//=> ['a/x/b', 'a/y/b', 'a/z/b']

console.log(braces.expand('{01..10}'));
//=> ['01','02','03','04','05','06','07','08','09','10']

列表

展开列表(像Bash的“set”):

console.log(braces('a/{foo,bar,baz}/*.js'));
//=> ['a/(foo|bar|baz)/*.js']

console.log(braces.expand('a/{foo,bar,baz}/*.js'));
//=> ['a/foo/*.js', 'a/bar/*.js', 'a/baz/*.js']

序列

扩展字符范围(如Bash "sequences"):

console.log(braces.expand('{1..3}')); // ['1', '2', '3']
console.log(braces.expand('a/{1..3}/b')); // ['a/1/b', 'a/2/b', 'a/3/b']
console.log(braces('{a..c}', { expand: true })); // ['a', 'b', 'c']
console.log(braces('foo/{a..c}', { expand: true })); // ['foo/a', 'foo/b', 'foo/c']

// supports zero-padded ranges
console.log(braces('a/{01..03}/b')); //=> ['a/(0[1-3])/b']
console.log(braces('a/{001..300}/b')); //=> ['a/(0{2}[1-9]|0[1-9][0-9]|[12][0-9]{2}|300)/b']

看到 fill-range 对于所有可用的范围扩展选项。

Steppped范围

步进或增量可以与范围一起使用:

console.log(braces.expand('{2..10..2}'));
//=> ['2', '4', '6', '8', '10']

console.log(braces('{2..10..2}'));
//=> ['(2|4|6|8|10)']

当 .optimize 方法,或 options.optimize 设置为true,则将序列传递给 到正则表达式范围 为扩张。

嵌套

大括号模式可以嵌套。每个扩展字符串的结果不排序,并保持从左到右的顺序。

“扩大”括号

console.log(braces.expand('a{b,c,/{x,y}}/e'));
//=> ['ab/e', 'ac/e', 'a/x/e', 'a/y/e']

console.log(braces.expand('a/{x,{1..5},y}/c'));
//=> ['a/x/c', 'a/1/c', 'a/2/c', 'a/3/c', 'a/4/c', 'a/5/c', 'a/y/c']

“优化”括号

console.log(braces('a{b,c,/{x,y}}/e'));
//=> ['a(b|c|/(x|y))/e']

console.log(braces('a/{x,{1..5},y}/c'));
//=> ['a/(x|([1-5])|y)/c']

逃离

逃离括号

如果出现以下情况,则不会展开或计算大括号模式 左括号或右括号被转义:

console.log(braces.expand('a\\{d,c,b}e'));
//=> ['a{d,c,b}e']

console.log(braces.expand('a{d,c,b\\}e'));
//=> ['a{d,c,b}e']

逃离逗号

大括号内的逗号也可以转义:

console.log(braces.expand('a{b\\,c}d'));
//=> ['a{b,c}d']

console.log(braces.expand('a{d\\,c,b}e'));
//=> ['ad,ce', 'abe']

单项

遵循bash约定,大括号模式在包含单个字符时也不会展开:

console.log(braces.expand('a{b}c'));
//=> ['a{b}c']

选项

options.maxLength

类型: Number

默认的: 10,000

描述限制输入字符串的长度。当输入字符串被生成或者你的应用程序允许用户传递一个字符串时很有用,等等。

console.log(braces('a/{b,c}/d', { maxLength: 3 })); //=> throws an error

options.expand

类型: Boolean

默认的: undefined

描述:生成一个“展开的”大括号模式(或者你可以使用 braces.expand() 方法,它做同样的事情)。

console.log(braces('a/{b,c}/d', { expand: true }));
//=> [ 'a/b/d', 'a/c/d' ]

options.nodupes

类型: Boolean

默认的: undefined

描述:从返回的数组中移除重复项。

options.rangeLimit

类型: Number

默认的: 1000

描述:为防止用户传递恶意模式,当 braces.expand() 是用来或 options.expand 为true,生成的范围将超过 rangeLimit。

你可以自定义 options.rangeLimit 或者设置为 Inifinity 完全禁用它。

例子

// pattern exceeds the "rangeLimit", so it's optimized automatically
console.log(braces.expand('{1..1000}'));
//=> ['([1-9]|[1-9][0-9]{1,2}|1000)']

// pattern does not exceed "rangeLimit", so it's NOT optimized
console.log(braces.expand('{1..100}'));
//=> ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24', '25', '26', '27', '28', '29', '30', '31', '32', '33', '34', '35', '36', '37', '38', '39', '40', '41', '42', '43', '44', '45', '46', '47', '48', '49', '50', '51', '52', '53', '54', '55', '56', '57', '58', '59', '60', '61', '62', '63', '64', '65', '66', '67', '68', '69', '70', '71', '72', '73', '74', '75', '76', '77', '78', '79', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89', '90', '91', '92', '93', '94', '95', '96', '97', '98', '99', '100']

options.transform

类型: Function

默认的: undefined

描述:自定义范围扩展。

示例:转换非数值

const alpha = braces.expand('x/{a..e}/y', {
  transform(value, index) {
    // When non-numeric values are passed, "value" is a character code.
    return 'foo/' + String.fromCharCode(value) + '-' + index;
  },
});
console.log(alpha);
//=> [ 'x/foo/a-0/y', 'x/foo/b-1/y', 'x/foo/c-2/y', 'x/foo/d-3/y', 'x/foo/e-4/y' ]

示例:转换数值

const numeric = braces.expand('{1..5}', {
  transform(value) {
    // when numeric values are passed, "value" is a number
    return 'foo/' + value * 2;
  },
});
console.log(numeric);
//=> [ 'foo/2', 'foo/4', 'foo/6', 'foo/8', 'foo/10' ]

options.quantifiers

类型: Boolean

默认的: undefined

描述:在正则表达式中,可以使用限定词来指定一个标记可以重复多少次。例如, a{1,3} 将与字母匹配 a 一到三次。

不幸的是,正则表达式量词恰好与 Bash列表

这个 quantifiers 选项告诉大括号何时检测 regex量词 在给定模式中定义的,而不是试图将它们展开为列表。

例子

const braces = require('braces');
console.log(braces('a/b{1,3}/{x,y,z}'));
//=> [ 'a/b(1|3)/(x|y|z)' ]
console.log(braces('a/b{1,3}/{x,y,z}', { quantifiers: true }));
//=> [ 'a/b{1,3}/(x|y|z)' ]
console.log(braces('a/b{1,3}/{x,y,z}', { quantifiers: true, expand: true }));
//=> [ 'a/b{1,3}/x', 'a/b{1,3}/y', 'a/b{1,3}/z' ]

options.keepEscaping

类型: Boolean

默认的: undefined

描述:不要从结果中去掉用于转义的反斜杠。

什么是“支撑扩张”?

大括号展开是unix shell中流行的一种参数展开,用于生成字符串列表,以及与通配符(globs)一起使用时的类正则表达式匹配。

除了“展开”,大括号也用于匹配。换句话说:

关于支撑扩展的更多信息 (点击展开)

大括号扩展主要有两种类型:

  1. 列表它们是用花括号内的逗号分隔值定义的: {a,b,c}
  2. 序列:它们是用起始值和结束值定义的,用两个点分隔: a{1..3}b. 可选地,可以传递第三个参数来定义要使用的“step”或增量: a{1..100..10}b. 这些有时也被称为“范围”。

下面是一些示例大括号模式来说明它们是如何工作的:

集

{a,b,c}       => a b c
{a,b,c}{1,2}  => a1 a2 b1 b2 c1 c2

序列

{1..9}        => 1 2 3 4 5 6 7 8 9
{4..-4}       => 4 3 2 1 0 -1 -2 -3 -4
{1..20..3}    => 1 4 7 10 13 16 19
{a..j}        => a b c d e f g h i j
{j..a}        => j i h g f e d c b a
{a..z..3}     => a d g j m p s v y

结合

集合和序列可以混合在一起或与任何其他字符串一起使用。

{a,b,c}{1..3}   => a1 a2 a3 b1 b2 b3 c1 c2 c3
foo/{a,b,c}/bar => foo/a/bar foo/b/bar foo/c/bar

事实上,大括号可以从相对简单的模式中“展开”,这使得它们非常适合快速生成测试fixture、文件路径和类似的用例。

括号匹配

除了…之外 扩张,大括号模式对于执行类似正则表达式的匹配也很有用。

例如,模式 foo/{1..3}/bar 将匹配以下任何字符串:

foo/1/bar
foo/2/bar
foo/3/bar

而不是:

baz/1/qux
baz/2/qux
baz/3/qux

大括号也可以与 一团模式 执行更高级的通配符匹配。例如,模式 */{1..3}/* 将匹配以下任何字符串:

foo/1/bar
foo/2/bar
foo/3/bar
baz/1/qux
baz/2/qux
baz/3/qux

支架匹配缺陷

虽然大括号模式提供了一种用户友好的匹配字符串范围或字符串集的方式,但也有一些主要的缺点和潜在的风险,您应该意识到。

tldr

“撑炸弹”

  • 支撑扩展会消耗大量的处理资源
  • 随着括号模式的增加 尺寸呈线性,扩展模式所需的系统资源呈指数级增长
  • 用户可能会意外(或故意)耗尽系统资源,导致相当于DoS攻击(好处:不需要编程知识!)

有关更详细的示例解释,请参阅 几何复杂性 部分。

解决方案

跳转到 性能部分 看看与其他库相比,大括号是如何解决这个问题的。

几何复杂性

至少,集合限制为两个元素的括号模式具有二次或 O(n^2) 的复杂性。但算法的复杂性随着集合数量的增加呈指数增长, 每个集合的元素,增加,即 O(n^c)。

例如,下面的集合演示了二次元(O(n^2)复杂性:

{1,2}{3,4}      => (2X2)    => 13 14 23 24
{1,2}{3,4}{5,6} => (2X2X2)  => 135 136 145 146 235 236 245 246

但是在集合中加入一个元素,我们得到一个n倍笛卡尔积 O(n^c) 复杂性:

{1,2,3}{4,5,6}{7,8,9} => (3X3X3) => 147 148 149 157 158 159 167 168 169 247 248
                                    249 257 258 259 267 268 269 347 348 349 357
                                    358 359 367 368 369

现在,想象一下如果每个元素都是n元组,复杂度会如何增长:

{1..100}{1..100}         => (100X100)     => 10,000 elements (38.4 kB)
{1..100}{1..100}{1..100} => (100X100X100) => 1,000,000 elements (5.76 MB)

尽管这些例子显然是人为的,但它们展示了大括号模式是如何迅速失控的。

更多的信息

有兴趣了解更多关于大括号展开的知识吗?

表演

大括号不仅速度快,而且比其他大括号扩展库更准确。

更好的算法

幸运的是,有一个解决方案 “支撑炸弹”问题: 当使用大括号模式进行匹配时,不要将其展开为数组。

相反,将模式转换为优化的正则表达式。这说起来容易做起来难,而且目前只有大括号库能做到这一点。

数字就是证据

随着模式复杂性的增加,Minimatch的速度会呈指数级增长,而大括号则不会。生成以下结果 braces() 和 minimatch.braceExpand(),分别。

模式牙套[minimatch] []
{1..9007199254740991}[^ 1]298 B (5 459μs女士)N / A(冻结)
{1..1000000000000000}41 B (1女士15μs)N / A(冻结)
{1..100000000000000}40 B (890μs)N / A(冻结)
{1..10000000000000}39 B (2 49μs女士)N / A(冻结)
{1..1000000000000}38 B (608μs)N / A(冻结)
{1..100000000000}37 B (397μs)N / A(冻结)
{1..10000000000}35 B (983μs)N / A(冻结)
{1..1000000000}34 B (798μs)N / A(冻结)
{1..100000000}33 B (733μs)N / A(冻结)
{1..10000000}32 B (5 632μs女士)78.89 MB (16s 388ms 569μs)
{1..1000000}31 B (1 381μs女士)6.89 MB (15秒496ms 887μs)
{1..100000}30 B (950μs)588.89 kB (146 921μs女士)
{1..10000}29 B (1 114μs女士)48.89 kB (14 187μs女士)
{1..1000}28 B (760μs)3.89 kB (1 453μs女士)
{1..100}22 B (345μs)291 B (196μs)
{1..10}10 B (533μs)20 B (37μs)
{1..3}7 B (190μs)5 B (μs) 27日

更快的算法

当您需要展开时,大括号仍然快得多。

生成以下结果 braces.expand() 和 minimatch.braceExpand()分别)

模式牙套[minimatch] []
{1..10000000}78.89 MB (2s 698ms 642μs)78.89 MB (18s 601ms 974μs)
{1..1000000}6.89 MB (458 576μs女士)6.89 MB (1s 491ms 621μs)
{1..100000}588.89 kB (20 728μs女士)588.89 kB (156 919μs女士)
{1..10000}48.89 kB (2 202μs女士)48.89 kB (13 641μs女士)
{1..1000}3.89 kB (1 796μs女士)3.89 kB (1 958μs女士)
{1..100}291 B (424μs)291 B (211μs)
{1..10}20 B (487μs)20 B (72μs)
{1..3}5 B (166μs)5 B (μs) 27日

如果你想自己进行比较,看看 测试/支持/ generate.js。

基准

运行基准测试

安装开发依赖项:

npm i -d && npm benchmark

最新的结果

在不牺牲性能的情况下,牙套更加精确。

● expand - range (expanded)
     braces x 53,167 ops/sec ±0.12% (102 runs sampled)
  minimatch x 11,378 ops/sec ±0.10% (102 runs sampled)
● expand - range (optimized for regex)
     braces x 373,442 ops/sec ±0.04% (100 runs sampled)
  minimatch x 3,262 ops/sec ±0.18% (100 runs sampled)
● expand - nested ranges (expanded)
     braces x 33,921 ops/sec ±0.09% (99 runs sampled)
  minimatch x 10,855 ops/sec ±0.28% (100 runs sampled)
● expand - nested ranges (optimized for regex)
     braces x 287,479 ops/sec ±0.52% (98 runs sampled)
  minimatch x 3,219 ops/sec ±0.28% (101 runs sampled)
● expand - set (expanded)
     braces x 238,243 ops/sec ±0.19% (97 runs sampled)
  minimatch x 538,268 ops/sec ±0.31% (96 runs sampled)
● expand - set (optimized for regex)
     braces x 321,844 ops/sec ±0.10% (97 runs sampled)
  minimatch x 140,600 ops/sec ±0.15% (100 runs sampled)
● expand - nested sets (expanded)
     braces x 165,371 ops/sec ±0.42% (96 runs sampled)
  minimatch x 337,720 ops/sec ±0.28% (100 runs sampled)
● expand - nested sets (optimized for regex)
     braces x 242,948 ops/sec ±0.12% (99 runs sampled)
  minimatch x 87,403 ops/sec ±0.79% (96 runs sampled)

关于

贡献

拉请求和明星总是受欢迎的。对于bug和特性请求, 请创建一个问题。

运行测试

运行和审查单元测试是熟悉库及其API的好方法。可以使用以下命令安装依赖项并运行测试:

$ npm install && npm test
建立文档

(这个项目的自述。Md由 动词请不要直接编辑自述文件。对自述文件的任何更改都必须在 .verb.md 自述文件模板)。

使用实例生成自述文件。

$ npm install -g verbose/verb#dev verb-generate-readme && verb

贡献者

提交贡献者
197jonschlinkert
4doowb
1es128
1eush77
1hemanth
1wtgtybhertgeghgtwtg

作者

Jon Schlinkert

许可证

版权所有©2019 Jon Schlinkert。 根据 麻省理工学院的许可。


该文件由 动词-生成-自述文件, v0.8.0,于2019年4月8日发布。

版本与发布记录

braces 共发布 38 个版本,首次发布于 2014/10/21;过去 12 个月发布了 0 个版本。

版本发布日期距今
3.0.3latest2024/05/212 年前
3.0.22019/04/177 年前
3.0.12019/04/107 年前
3.0.02019/04/097 年前
2.3.22018/04/088 年前
2.3.12018/02/188 年前

关于 braces 的常见问题

braces 是什么?

类似bash的大括号展开,在JavaScript中实现。比其他大括号扩展库更安全,完全支持Bash 4.3大括号规范,而不牺牲速度。

如何安装 braces?

在项目目录运行 npm install braces,或使用 pnpm add / yarn add / bun add。

braces 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/braces 是否存在。

braces 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

braces 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=8。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

braces 可以商用吗?

braces 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

braces 的下载量有多少?

根据 npm 官方下载统计,braces 在 2026/10/04 – 2026/11/02 这 30 天内被下载 649,897,060 次,日均约 21,663,235 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

braces 还在维护吗?

最新版本 3.0.3 发布于 2024/05/21(2 年前);至今共发布 38 个版本,其中过去 12 个月发布了 0 个;首次发布于 2014/10/21。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。