{"id":29027321,"url":"https://github.com/rameel/ramstack.globbing","last_synced_at":"2025-06-26T06:05:25.441Z","repository":{"id":247503977,"uuid":"826021921","full_name":"rameel/ramstack.globbing","owner":"rameel","description":"Fast and zero-allocation .NET globbing library for matching file paths using glob patterns","archived":false,"fork":false,"pushed_at":"2024-08-26T19:46:04.000Z","size":195,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-09T03:57:15.630Z","etag":null,"topics":["glob","globbing"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rameel.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-09T00:58:57.000Z","updated_at":"2024-09-24T16:21:42.000Z","dependencies_parsed_at":"2024-08-07T14:18:43.051Z","dependency_job_id":"7755be5b-b49c-43e1-b3e9-d27a79008d48","html_url":"https://github.com/rameel/ramstack.globbing","commit_stats":null,"previous_names":["rameel/ramstack.globbing"],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/rameel/ramstack.globbing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.globbing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.globbing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.globbing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.globbing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rameel","download_url":"https://codeload.github.com/rameel/ramstack.globbing/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rameel%2Framstack.globbing/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262010867,"owners_count":23244414,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["glob","globbing"],"created_at":"2025-06-26T06:05:24.801Z","updated_at":"2025-06-26T06:05:25.407Z","avatar_url":"https://github.com/rameel.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Ramstack.Globbing\r\n\r\nFast and zero-allocation .NET globbing library for matching file paths using [glob patterns](https://en.wikipedia.org/wiki/Glob_(programming)).\r\nNo external dependencies.\r\n\r\n## Getting Started\r\n\r\nTo install the `Ramstack.Globbing` [NuGet package](https://www.nuget.org/packages/Ramstack.Globbing) to your project, run the following command:\r\n```console\r\ndotnet add package Ramstack.Globbing\r\n```\r\n\r\n## Usage\r\n\r\n```csharp\r\nbool result = Matcher.IsMatch(\"wiki/section-1/start.md\", \"wiki/**/*.md\");\r\n```\r\nThe `IsMatch` method attempts to match the specified path against the provided wildcard pattern.\r\n\r\nBy default, the system's default path separators are used. You can override this behavior by specifying one of the following flags:\r\n\r\n| Name    | Description                                                                                                                                                                                                                              |\r\n|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\r\n| Auto    | Automatically determines whether to treat backslashes (`\\ `) as escape sequences or path separators based on the platform's separator convention.                                                                                        |\r\n| Windows | Treats backslashes (`\\ `) as path separators instead of escape sequences.\u003cbr\u003eProvides behavior consistent with Windows-style paths.\u003cbr\u003eBoth backslashes (`\\ `) and forward slashes (`/`) are considered as path separators in this mode. |\r\n| Unix    | Treats backslashes (`\\ `) as escape sequences, allowing for special character escaping.\u003cbr\u003eProvides behavior consistent with Unix-style paths.                                                                                           |\r\n\r\nExample with a specific flag:\r\n```csharp\r\nbool result = Matcher.IsMatch(\"wiki/section-1/start.md\", @\"wiki\\**\\*.md\", MatchFlags.Windows);\r\n```\r\n\r\n## Patterns\r\nFrom [Wikipedia](https://en.wikipedia.org/wiki/Glob_(programming)#Syntax)\r\n\r\n| Pattern | Description                                                                  | Example      | Matches                                                  | Does not match                        |\r\n|---------|------------------------------------------------------------------------------|--------------|----------------------------------------------------------|---------------------------------------|\r\n| *       | matches any number of any characters including none                          | Law*         | Law, Laws, or Lawyer                                     | GrokLaw, La, Law/foo or aw            |\r\n|         |                                                                              | \\*Law\\*      | Law, GrokLaw, or Lawyer.                                 | La, or aw                             |\r\n| ?       | matches any single character                                                 | ?at          | Cat, cat, Bat or bat                                     | at                                    |\r\n| [abc]   | matches one character given in the bracket                                   | [CB]at       | Cat or Bat                                               | cat, bat or CBat                      |\r\n| [a-z]   | matches one character from the (locale-dependent) range given in the bracket | Letter[0-9]  | Letter0, Letter1, Letter2 up to Letter9                  | Letters, Letter or Letter10           |\r\n| [!abc]  | matches one character that is not given in the bracket                       | [!C]at       | Bat, bat, or cat                                         | Cat                                   |\r\n| [!a-z]  | matches one character that is not from the range given in the bracket        | Letter[!3-5] | Letter1, Letter2, Letter6 up to Letter9 and Letterx etc. | Letter3, Letter4, Letter5 or Letterxx |\r\n\r\n### Pattern specific for directories\r\n\r\n| Pattern | Description                                         | Example | Matches                        | Does not match |\r\n|---------|-----------------------------------------------------|---------|--------------------------------|----------------|\r\n| **      | matches any number of path segments including none  | **/Law  | dir1/dir2/Law, dir1/Law or Law | dir1/La        |\r\n\r\n### Brace patterns\r\n\r\nBrace patterns allow for matching multiple alternatives in a single pattern. Here are some key features:\r\n\r\n| Pattern        | Description                              | Example             | Matches                                         | Does not match |\r\n|----------------|------------------------------------------|---------------------|-------------------------------------------------|----------------|\r\n| {a,b,c}        | matches any of the comma-separated terms | file.{jpg,png}      | file.jpg, file.png                              | file.gif       |\r\n| {src,test{s,}} | supports nested brace patterns           | {src,test{s,}}/*.cs | src/main.cs, tests/unit.cs, test/integration.cs | doc/readme.cs  |\r\n| {main,,test}   | supports empty alternatives              | {main,,test}1.txt   | main1.txt, test1.txt, 1.txt                     | file1.txt      |\r\n| {[sS]rc,test*} | supports full glob pattern within braces | {[sS]rc,test*}/*.cs | src/app.cs, Src/main.cs, testing/script.cs      | lib/util.cs    |\r\n\r\n* Empty alternatives are valid, e.g., `{src,test,}` will also match paths without the listed prefixes.\r\n* Brace patterns can be nested, allowing for complex matching scenarios.\r\n* Full glob patterns can be used within braces, providing powerful and flexible matching capabilities.\r\n\r\n## Escaping characters\r\n\r\nThe meta characters `?`, `*`, `[`, `\\ ` can be escaped by using the `[]`, which means *match one character listed in the bracket*.\r\n* `[[]` matches the literal `[`\r\n* `[*]` matches the literal `*`\r\n\r\nThis works when using any `MatchFlags` (`Windows` or `Unix`).\r\nWhen using `MatchFlags.Unix`, an additional escape character (`\\`) is available:\r\n* `\\[` matches the literal `[`\r\n* `\\*` matches the literal `*`\r\n\r\n## Notes\r\n* Leading and trailing path separators are ignored.\r\n* Consecutive path separators are counted as one separator.\r\n\r\n### Special cases\r\n* At the root level, an empty path segment is valid, which can be represented by patterns like \"*\".\r\n* At any deeper level, an empty segment indicates that a required directory or file is missing,\r\n  making the path invalid for patterns expecting something at that level.\r\n\r\n| Pattern  | Matches     | Does not match | Explanation                                                                         |\r\n|----------|-------------|----------------|-------------------------------------------------------------------------------------|\r\n| `*`      | `foo`, `\"\"` |                | Matches everything, e.g. empty string                                               |\r\n| `*/*`    | `a/b`,`b/c` | `a`,`b`,`foo`  | Requires at least one directory level, so `a` is not a match                        |\r\n| `*/{,b}` | `a/b`       | `a`,`b`,`foo`  | Requires a directory or a specific file `b` at the next level, so `a` doesn't match |\r\n\r\n:bulb: This means that the patterns `*/{}` and `*/{,}` cannot match any path due to the rule: an empty segment is not allowed beyond the root level.\r\n\r\n## Optimizations\r\nWe use optimizations that prevent quadratic behavior in scenarios like the pattern `a*a*a*a*a*a*a*a*a*c`\r\nmatching against the text `aaaaaaaaaaaaaaa...aaaa...aaa`.\r\nSimilarly, for the `a/**/a/**/a/**/.../a/**/a/**/a/**/b` pattern matching against `a/a/a/a/.../a/.../a`.\r\n\r\n## File traversal\r\n\r\nThe `Files` class provides functionality for traversing the file system and retrieving lists of files and directories\r\nbased on specified glob patterns. This allows for flexible and efficient file and directory enumeration.\r\n\r\n```csharp\r\nusing Ramstack.Globbing.Traversal;\r\n\r\n// List all *.cs files\r\nvar files = Files.EnumerateFiles(@\"/path/to/directory\", \"**/*.cs\");\r\nforeach (var file in files)\r\n    Console.WriteLine(file);\r\n\r\n// List all *.cs files except in tests directory\r\nvar files = Files.EnumerateFiles(@\"/path/to/directory\", \"**/*.cs\", \"tests\");\r\nforeach (var file in files)\r\n    Console.WriteLine(file);\r\n```\r\nSupport for multiple patterns is also included:\r\n\r\n```csharp\r\nusing Ramstack.Globbing.Traversal;\r\n\r\n// List all *.cs files\r\nvar files = Files.EnumerateFiles(@\"/path/to/directory\", [\"src/**/*.cs\", \"lib/**/*.cs\"], [\"**/tests\"]);\r\nforeach (var file in files)\r\n    Console.WriteLine(file);\r\n```\r\n\r\nThere are overloads that take a `TraversalOptions` allowing you to set additional options when traversing the file system,\r\nsuch as:\r\n- Filtering out specific attributes\r\n- Ignoring inaccessible files\r\n- Maximum recursion depth\r\n\r\nThese methods are quite efficient in terms of speed, memory consumption, and GC pressure.\r\nHere are the benchmarking results for the [dotnet/runtime](https://github.com/dotnet/runtime) repository folder, which contained\r\n59194 files at the time of testing. The search was for `*.md` files:\r\n\r\n```\r\nBenchmarkDotNet v0.13.12, Windows 11 (10.0.22631.3880/23H2/2023Update/SunValley3)\r\nAMD Ryzen 9 5900X, 1 CPU, 24 logical and 12 physical cores\r\n.NET SDK 9.0.100-preview.6.24328.19\r\n  [Host]     : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2\r\n  Job-GMSEBO : .NET 8.0.7 (8.0.724.31311), X64 RyuJIT AVX2\r\n\r\nRuntime=.NET 8.0\r\n\r\n| Method                             | Mean     | Error   | StdDev  | Gen0      | Gen1     | Allocated |\r\n|----------------------------------- |---------:|--------:|--------:|----------:|---------:|----------:|\r\n| \u003e\u003e Ramstack_Files_EnumerateFiles   | 154.4 ms | 0.67 ms | 0.59 ms |         - |        - |   2.33 MB |\r\n| Microsoft_Directory_EnumerateFiles | 149.1 ms | 0.74 ms | 0.66 ms |         - |        - |   2.33 MB |\r\n| Microsoft_FileSystemGlobbing       | 176.6 ms | 1.16 ms | 1.08 ms | 2000.0000 | 333.3333 |  35.99 MB |\r\n```\r\n\r\nAs you can see, the code is as fast as a direct search using `Directory.EnumerateFiles` and consumes the same amount of memory.\r\nThis makes sense, since the implementation of `Files.EnumerateFiles` uses the same `FileSystemEnumerable` class.\r\n\r\nAlso, corresponding extension methods added for `DirectoryInfo`, which also allow you to leverage\r\nthe full power of glob patterns when searching for files.\r\n\r\n## Custom File System Support\r\n\r\nThe `FileTreeEnumerable` class provides support for custom file systems with glob pattern matching capabilities.\r\nHere is an example of its usage:\r\n```csharp\r\n// --------------------------------------------------------------------\r\n// As an example, we'll use the existing DirectoryInfo/FileInfo classes\r\n\r\nvar root = new DirectoryInfo(@\"D:\\Projects\\dotnet.runtime\");\r\nvar enumeration = new FileTreeEnumerable\u003cFileSystemInfo, string\u003e(root)\r\n{\r\n    Patterns = [\"**/*.cs\"],\r\n    Excludes = [\"**/{bin,obj}\"],\r\n    FileNameSelector = info =\u003e info.Name,\r\n    ShouldRecursePredicate = info =\u003e info is DirectoryInfo,\r\n    // The following predicate used to filter the files\r\n    ShouldIncludePredicate = info =\u003e info is FileInfo,\r\n    ChildrenSelector = info =\u003e ((DirectoryInfo)info).EnumerateFileSystemInfos(),\r\n    // Returns the full path of the file\r\n    ResultSelector = info =\u003e info.FullName\r\n};\r\n\r\n// Prints all csharp files\r\nforeach (string filePath in enumeration)\r\n    Console.WriteLine(filePath);\r\n```\r\n\r\n### Asynchronous Enumeration\r\nThe `FileTreeAsyncEnumerable` class provides similar functionality to `FileTreeEnumerable`,\r\nbut supports asynchronous enumeration for remote file systems as an example.\r\n\r\nHere's an example of how to use `FileTreeAsyncEnumerable`:\r\n\r\n```csharp\r\n// ---------------------------------------------------\r\n// Assuming we have an IAsyncFileSystem implementation\r\n\r\nvar root = cloudFS.GetDirectory(@\"/projects/dotnet.runtime\");\r\nvar enumeration = new FileTreeAsyncEnumerable\u003cIAsyncFileSystemEntry, string\u003e(root)\r\n{\r\n    Patterns = [\"**/*.cs\"],\r\n    Excludes = [\"**/{bin,obj}\"],\r\n    FileNameSelector = entry =\u003e entry.Name,\r\n    ShouldRecursePredicate = entry =\u003e entry is IDirectory,\r\n    ShouldIncludePredicate = entry =\u003e entry is IFile,\r\n    ChildrenSelector = (entry, token) =\u003e ((IDirectory)entry).GetFileEntriesAsync(token),\r\n    ResultSelector = entry =\u003e entry.FullPath\r\n};\r\n\r\n// Prints all csharp files asynchronously\r\nawait foreach (string filePath in enumeration)\r\n    Console.WriteLine(filePath);\r\n```\r\n\r\n\r\n## Supported versions\r\n\r\n|      | Version |\r\n|------|---------|\r\n| .NET | 6, 7, 8 |\r\n\r\n## Contributions\r\n\r\nBug reports and contributions are welcome.\r\n\r\n## License\r\nThis package is released as open source under the **MIT License**. See the [LICENSE](LICENSE) file for more details.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frameel%2Framstack.globbing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frameel%2Framstack.globbing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frameel%2Framstack.globbing/lists"}