Glob Class
Glob patterns specify sets of filenames with wildcard characters. Supported syntaxes:
| Wildcard | Description |
|---|---|
| * | matches any number of characters including none, excluding directory separator |
| ? | matches a single character |
| [abc] | matches one character in the brackets |
| [!abc] | matches any character not in the brackets. GlobDialect.Git, GlobDialect.Posix and GlobDialect.PosixPath also accept [^abc]. |
| [a-z] | matches one character from the range given in the brackets. With GlobOptions.IgnoreCase, a character matches when it, its lowercase form or its uppercase form is in the range. |
| [!a-z] | matches one character that is not from the range given in the brackets, using the same rule as [a-z] for GlobOptions.IgnoreCase. |
| [[:alpha:]] | matches one character of a POSIX character class. Only supported by GlobDialect.Git, GlobDialect.Posix and GlobDialect.PosixPath. The supported classes are alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper and xdigit. With GlobOptions.IgnoreCase, upper and lower match a letter of either case. |
| [[=a=]] [[.a.]] | an equivalence class and a collating symbol, which both stand for the character they hold. Only supported by GlobDialect.Posix and GlobDialect.PosixPath. A collating symbol can be a range bound: [[.-.]-0]. |
| {abc,*.cs} | comma-delimited alternatives, matches 'abc' or a name ending with '.cs'. An alternative can hold wildcards, bracket expressions and other braces, and a '/' or a '**', as in {src/**,tests}/*.cs. Only supported by GlobDialect.Standard; the other dialects read the braces as ordinary characters. |
| ** | matches zero or more directories when it makes a whole path segment. A trailing ** matches at least one segment. The POSIX dialects read it as a *. |
| !pattern | leading '!' negates the pattern. Only supported by GlobDialect.Standard and GlobDialect.Git. |
| \x | escapes the following character. For instance, '\*' matches the literal character '*' instead of being a wildcard. GlobDialect.Git and the POSIX dialects also read an escape in a bracket expression. GlobDialect.MSBuild reads '\' as a path separator and escapes a character with %XX instead. |
If the pattern ends with a /, only directories are matched. Otherwise, only files are matched. A GlobDialect.Git pattern matches both a file and a directory, and one ending with a / matches the directory itself as well as everything below it. A GlobDialect.Posix pattern matches a plain string, whatever the kind of item.
GlobDialect.Git, GlobDialect.MSBuild, GlobDialect.Posix and GlobDialect.PosixPath follow the behavior of git, MSBuild and fnmatch(3), which the tests check against corpora produced by those implementations. The exceptions are deliberate: characters are compared as UTF-16 code units (git compares the bytes of their UTF-8 encoding), a path ending with a / is a directory (fnmatch compares strings), and a pattern that can never match anything, such as one holding an unknown character class, is rejected.
The cost of a single Glob.IsMatch call is polynomial in the length of the pattern and of the path, whatever the number of wildcards.
public sealed class Glob : IGlobEvaluatableExample
Parse a glob pattern and check if a path matches:
var glob = Glob.Parse("src/**/*.txt", GlobDialect.Standard);
Assert.True(glob.IsMatch("src/folder/file.txt"));
Assert.False(glob.IsMatch("docs/file.txt"));Enumerate files that match a glob pattern:
var glob = Glob.Parse("**/*.cs", GlobDialect.Standard, GlobOptions.IgnoreCase);
foreach (var file in glob.EnumerateFiles("C:/MyProject"))
{
Console.WriteLine(file);
}See also
- Implements
Properties
| Name | Description |
|---|---|
| Meziantou.Framework.Globbing.IGlobEvaluatable.CanMatchDirectories | |
| Meziantou.Framework.Globbing.IGlobEvaluatable.CanMatchFiles | |
| Meziantou.Framework.Globbing.IGlobEvaluatable.TraverseDirectories | |
| Mode | Gets the glob mode indicating whether this pattern includes or excludes matches. |
Meziantou.Framework.Globbing.IGlobEvaluatable.CanMatchDirectories
Glob.csMeziantou.Framework.Globbing.IGlobEvaluatable.CanMatchFiles
Glob.csMeziantou.Framework.Globbing.IGlobEvaluatable.TraverseDirectories
Glob.csMode
Glob.csMethods
| Name | Description |
|---|---|
| Escape(ReadOnlySpan<char>, GlobDialect) | Escapes text so that it can be used as a pattern, or as a part of a pattern, that matches exactly this text. |
| Escape(string, GlobDialect) | Escapes text so that it can be used as a pattern, or as a part of a pattern, that matches exactly this text. |
| IsMatch(ReadOnlySpan<char>, ReadOnlySpan<char>, PathItemType?) | Determines whether the specified path matches this glob pattern. |
| IsPartialMatch(ReadOnlySpan<char>, ReadOnlySpan<char>) | Determines whether a directory should be recursed into when enumerating files. |
| Parse(ReadOnlySpan<char>, GlobDialect, GlobOptions) | Parses a glob pattern string. |
| Parse(string, GlobDialect, GlobOptions) | Parses a glob pattern string. |
| ToString() | Returns a pattern that parses back, with the same dialect and options, into a glob that matches the same paths. |
| TryParse(ReadOnlySpan<char>, GlobDialect, GlobOptions, Glob?) | Attempts to parse a glob pattern string. |
| TryParse(string, GlobDialect, GlobOptions, Glob?) | Attempts to parse a glob pattern string. |
| TrySplitBasePath(string?, Glob?) | Splits the pattern into its base path, the leading directories that do not hold any wildcard, and a pattern that matches the rest of the path relative to that base path. |
Escape overloads
Escape(ReadOnlySpan<char>, GlobDialect)
Glob.csEscapes text so that it can be used as a pattern, or as a part of a pattern, that matches exactly this text.
public static string Escape(ReadOnlySpan<char> text, GlobDialect dialect)Parameters
textReadOnlySpan<char>- The text to escape, such as a file name or a relative path.
dialectGlobDialect- The dialect of the pattern.
Returns
string A pattern that matches text.
Remarks
See Glob.Escape.
Escape(string, GlobDialect)
Glob.csEscapes text so that it can be used as a pattern, or as a part of a pattern, that matches exactly this text.
public static string Escape(string text, GlobDialect dialect)Parameters
textstring- The text to escape, such as a file name or a relative path.
dialectGlobDialect- The dialect of the pattern.
Returns
string A pattern that matches text.
Remarks
Every character that dialect reads as syntax is escaped, as well as a leading ! (and # for GlobDialect.Git) and a trailing space for GlobDialect.Git. GlobDialect.MSBuild also escapes the characters that have a meaning in a project file (;, $, @, ', ( and )).
A path separator stays a separator: /, \ on Windows, and both for GlobDialect.MSBuild. GlobDialect.Posix matches a plain string, so it has no separator. As for any GlobDialect.Git pattern, a result without a / matches the name at any depth; prepend a / to anchor it to the root.
Example
// Build a pattern from a folder name that holds special characters
var pattern = Glob.Escape("Reports [2024]", GlobDialect.Standard) + "/**/*.pdf";
Assert.Equal(@"Reports \[2024]/**/*.pdf", pattern);
var glob = Glob.Parse(pattern, GlobDialect.Standard);
Assert.True(glob.IsMatch("Reports [2024]/Q1/summary.pdf"));
Assert.False(glob.IsMatch("Reports 2/Q1/summary.pdf"));
// Each dialect has its own escaping rules
Assert.Equal("100%25 done.txt", Glob.Escape("100% done.txt", GlobDialect.MSBuild));
Assert.Equal(@"\#notes.txt", Glob.Escape("#notes.txt", GlobDialect.Git));IsMatch(ReadOnlySpan<char>, ReadOnlySpan<char>, PathItemType?)
Glob.csDetermines whether the specified path matches this glob pattern.
public bool IsMatch(ReadOnlySpan<char> directory, ReadOnlySpan<char> filename, PathItemType? itemType)Parameters
directoryReadOnlySpan<char>- The directory part of the path to match.
filenameReadOnlySpan<char>- The filename part of the path to match.
itemTypePathItemType?- The type of the path item (file or directory), or
nullif unknown.
Returns
bool true if the path matches the pattern; otherwise, false.
IsPartialMatch(ReadOnlySpan<char>, ReadOnlySpan<char>)
Glob.csDetermines whether a directory should be recursed into when enumerating files.
public bool IsPartialMatch(ReadOnlySpan<char> folderPath, ReadOnlySpan<char> filename)Parameters
folderPathReadOnlySpan<char>- The folder path to check.
filenameReadOnlySpan<char>- The filename part of the path to check.
Returns
bool true if the directory could contain matches; otherwise, false.
Parse overloads
Parse(ReadOnlySpan<char>, GlobDialect, GlobOptions)
Glob.csParses a glob pattern string.
public static Glob Parse(ReadOnlySpan<char> pattern, GlobDialect dialect, GlobOptions options = GlobOptions.None)Parameters
patternReadOnlySpan<char>- The glob pattern to parse.
dialectGlobDialect- The glob pattern dialect to use.
optionsGlobOptions- Options for controlling pattern parsing behavior.
Returns
Glob A Glob object representing the parsed pattern.
Exceptions
ArgumentException- The pattern is invalid.
Parse(string, GlobDialect, GlobOptions)
Glob.csParses a glob pattern string.
public static Glob Parse(string pattern, GlobDialect dialect, GlobOptions options = GlobOptions.None)Parameters
patternstring- The glob pattern to parse.
dialectGlobDialect- The glob pattern dialect to use.
optionsGlobOptions- Options for controlling pattern parsing behavior.
Returns
Glob A Glob object representing the parsed pattern.
Exceptions
ArgumentException- The pattern is invalid.
ToString()
Glob.csTryParse overloads
TryParse(ReadOnlySpan<char>, GlobDialect, GlobOptions, Glob?)
Glob.csAttempts to parse a glob pattern string.
public static bool TryParse(ReadOnlySpan<char> pattern, GlobDialect dialect, GlobOptions options, out Glob? result)Parameters
patternReadOnlySpan<char>- The glob pattern to parse.
dialectGlobDialect- The glob pattern dialect to use.
optionsGlobOptions- Options for controlling pattern parsing behavior.
resultGlob?- When this method returns, contains the parsed
Globif parsing succeeded, ornullif parsing failed.
Returns
bool true if the pattern was parsed successfully; otherwise, false.
TryParse(string, GlobDialect, GlobOptions, Glob?)
Glob.csAttempts to parse a glob pattern string.
public static bool TryParse(string pattern, GlobDialect dialect, GlobOptions options, out Glob? result)Parameters
patternstring- The glob pattern to parse.
dialectGlobDialect- The glob pattern dialect to use.
optionsGlobOptions- Options for controlling pattern parsing behavior.
resultGlob?- When this method returns, contains the parsed
Globif parsing succeeded, ornullif parsing failed.
Returns
bool true if the pattern was parsed successfully; otherwise, false.
TrySplitBasePath(string?, Glob?)
Glob.csSplits the pattern into its base path, the leading directories that do not hold any wildcard, and a pattern that matches the rest of the path relative to that base path.
Parameters
basePathstring?- When this method returns
true, the base path, with/as the separator. It starts with a/for an absolute pattern, and with..for anGlobDialect.MSBuildpattern that goes up from the directory. relativeGlobGlob?- When this method returns
true, a glob with the same dialect, options and mode that matches a path relative tobasePath: a pathbasePath/pathmatches this glob whenpathmatchesrelativeGlob.
Returns
bool true if the pattern starts with at least one literal directory; otherwise, false.
Remarks
The last segment of the pattern, which matches the name of the item, is never part of the base path. A directory is not part of the base path when it does not have a single spelling: one holding a letter when GlobOptions.IgnoreCase is set, a . or .. directory (except a leading .. for GlobDialect.MSBuild), or one holding a path separator of the current platform. A GlobDialect.Posix pattern never has a base path, and a GlobDialect.Git pattern has one only when it is anchored.
Example
var glob = Glob.Parse("src/app/**/*.cs", GlobDialect.Standard);
Assert.True(glob.TrySplitBasePath(out var basePath, out var relativeGlob));
Assert.Equal("src/app", basePath);
Assert.Equal("**/*.cs", relativeGlob.ToString());
Assert.True(relativeGlob.IsMatch("Models/User.cs"));
// MSBuild resolves a leading '..' against the directory
Assert.True(Glob.Parse("../shared/*.cs", GlobDialect.MSBuild).TrySplitBasePath(out basePath, out _));
Assert.Equal("../shared", basePath);
// The pattern starts with a wildcard
Assert.False(Glob.Parse("**/*.cs", GlobDialect.Standard).TrySplitBasePath(out _, out _));