A fast (probably the fastest) globbing library for .NET.
Branch | Build Status | NuGet |
---|---|---|
Master | ||
Develop |
This library does not use Regex - I wanted to make something much faster.
The latest benchmarks show that DotNet.Glob signficantly outperforms Regex.
The benchmarks use BenchmarkDotNet and can be located inside this repo. Just dotnet run
them. Some Benchmark results have also been published on the wiki: https://github.com/dazinator/DotNet.Glob/wiki/Benchmarks-(vs-Compiled-Regex)
- Install the NuGet package.
Install-Package DotNet.Glob
- Add using statement:
using DotNet.Globbing;
- Parse a glob from a pattern
var glob = Glob.Parse("p?th/*a[bcd]b[e-g]a[1-4][!wxyz][!a-c][!1-3].*");
var isMatch = glob.IsMatch("pAth/fooooacbfa2vd4.txt");
By default, when your glob pattern is parsed, DotNet.Glob
will only parse literal characters which are valid for path / directory names.
These are:
- Any Letter or Digit
.
,!
,#
,-
,;
,=
,@
,~
,_
,:
This is optimised for matching against paths / directory strings.
However starting in 1.6.4
you can override this behaviour so that you can match on arbitrary string containing other characters:
// Overide the default options globally for all matche:
GlobParseOptions.Default.AllowInvalidPathCharacters = true;
DotNet.Globbing.Glob.Parse("\"Stuff*").IsMatch("\"Stuff"); // true;
You can also just set this behaviour on a per match basis:
var globParseOptions = new GlobParseOptions() { AllowInvalidPathCharacters = true };
DotNet.Globbing.Glob.Parse("\"Stuff*", globParseOptions).IsMatch("\"Stuff"); // true;
You can also use the GlobBuilder
class if you wish to build up a glob using a fluent syntax.
This is also more efficient as it avoids having to parse the glob from a string pattern.
So to build the following glob pattern: /foo?\\*[abc][!1-3].txt
:
var glob = new GlobBuilder()
.PathSeperator()
.Literal("foo")
.AnyCharacter()
.PathSeperator(PathSeperatorKind.BackwardSlash)
.Wildcard()
.OneOf('a', 'b', 'c')
.NumberNotInRange('1', '3')
.Literal(".txt")
.ToGlob();
var isMatch = glob.IsMatch(@"/fooa\\barrra4.txt"); // returns true.
The following patterns are supported (from wikipedia):
Wildcard | Description | Example | Matches | Does not match |
---|---|---|---|---|
* | matches any number of any characters including none | Law* | Law, Laws, or Lawyer | |
? | matches any single character | ?at | Cat, cat, Bat or bat | at |
[abc] | matches one character given in the bracket | [CB]at | Cat or Bat | cat or bat |
[a-z] | matches one character from the range given in the bracket | Letter[0-9] | Letter0, Letter1, Letter2 up to Letter9 | Letters, Letter or Letter10 |
[!abc] | matches one character that is not given in the bracket | [!C]at | Bat, bat, or cat | Cat |
[!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 |
In addition, DotNet Glob also supports:
Wildcard | Description | Example | Matches | Does not match |
---|---|---|---|---|
** |
matches any number of path / directory segments. When used must be the only contents of a segment. | /**/some.* | /foo/bar/bah/some.txt, /some.txt, or /foo/some.txt |
Given a glob, you can generate random matches, or non matches, for that glob.
For example, given the glob pattern /f?o/bar/**/*.txt
you could generate matching strings like /foo/bar/ajawd/awdaw/adw-ad.txt
or random non matching strings.
var dotnetGlob = Glob.Parse(pattern);
var generator = new GlobMatchStringGenerator(dotnetGlob.Tokens);
for (int i = 0; i < 10; i++)
{
var testString = generator.GenerateRandomMatch();
var result = dotnetGlob.IsMatch(testString);
// result is always true.
// generate a non match.
testString = generator.GenerateRandomNonMatch();
var result = dotnetGlob.IsMatch(testString);
// result is always false.
}
The IsMatch
method just returns you a boolean. If you require more in-depth information about the match including which tokens were matched, or failed to match, you can do this:
MatchInfo match = glob.Match(somestring);
You can then inspect the MatchInfo
which holds all of those useful details.