A .NET library for filtering text using glob patterns, regular expressions, and fuzzy matching
ktsu.TextFilter is a .NET library that provides methods for filtering text based on different filter types and match options. It supports glob patterns, regular expressions, and fuzzy matching to help you efficiently filter and search through collections of strings.
- Glob Pattern Matching: Filter text using glob patterns with optional, required, and excluded tokens.
- Regular Expression Matching: Filter text using regular expressions.
- Fuzzy Matching: Rank text based on how well it matches a fuzzy pattern.
- Customizable Match Options: Match by whole string, all words, or any word.
- Case Sensitivity: Opt into case-insensitive glob and regex matching; case sensitive by default.
Install-Package ktsu.TextFilterdotnet add package ktsu.TextFilter<PackageReference Include="ktsu.TextFilter" Version="x.y.z" />using ktsu.TextFilter;
string text = "Hello, World!";
string pattern = "Hello*";
bool isMatch = TextFilter.IsMatch(text, pattern);using ktsu.TextFilter;
string[] texts = new string[] { "Hello, World!", "Goodbye, World!" };
string pattern = "Hello*";
IEnumerable<string> matches = TextFilter.Filter(texts, pattern);using ktsu.TextFilter;
string[] texts = new string[] { "Hello, World!", "Goodbye, World!" };
string pattern = "Hello";
IEnumerable<string> ranked = TextFilter.Rank(texts, pattern);You can customize how matching is performed using the TextFilterMatchOptions enum. The default is
ByWordAny:
using ktsu.TextFilter;
string text = "Hello beautiful world";
string pattern = "hello world";
// Match by any word in the pattern (the default)
bool anyWordMatch = TextFilter.IsMatch(text, pattern,
TextFilterType.Glob, TextFilterMatchOptions.ByWordAny); // true
// Match by all words in the pattern
bool allWordsMatch = TextFilter.IsMatch(text, pattern,
TextFilterType.Glob, TextFilterMatchOptions.ByWordAll); // false
// Match the entire string
bool wholeStringMatch = TextFilter.IsMatch(text, pattern,
TextFilterType.Glob, TextFilterMatchOptions.ByWholeString); // falseGlob and regular expression matching are case sensitive by default. Pass
TextFilterCaseSensitivity.CaseInsensitive to fold case on both the text and the pattern:
using ktsu.TextFilter;
// Case sensitive (the default) - a camera writes IMG_1234.JPG, so this does not match
bool sensitive = TextFilter.IsMatch("IMG_1234.JPG", "*.jpg",
TextFilterType.Glob, TextFilterMatchOptions.ByWholeString); // false
// Case insensitive
bool insensitive = TextFilter.IsMatch("IMG_1234.JPG", "*.jpg",
TextFilterType.Glob, TextFilterMatchOptions.ByWholeString,
TextFilterCaseSensitivity.CaseInsensitive); // trueThe setting is available on IsMatch, Filter, DoesMatchGlob, DoesMatchRegex,
AnyTokenMatchesGlobFilter and AllTokensMatchGlobFilter, and applies to required and excluded
tokens as well as optional ones.
TextFilterType.Fuzzy does not take the setting: fuzzy matching is always case insensitive.
A glob token can contain a bracket class that matches one character: [abc], a range such as
[0-9], or a mix such as [0-9a-f]. A class that opens with ! or ^ is negated, so x[!a] and
x[^a] both match xb but not xa. A ^ anywhere else in a class is an ordinary member: x[a^]
matches x^.
Case is folded invariantly, so the answer does not depend on the calling thread's CurrentCulture.
That matters for the dotted and dotless I: under a Turkish culture, i and I are not each other's
case pair, and a culture-sensitive fold would stop a filter of img matching IMG_1234.JPG on a
machine whose locale happens to be tr-TR. A filter pattern is machine text rather than prose, so
it folds the same way everywhere.
TextFilter supports different filter types:
using ktsu.TextFilter;
string text = "Hello, World!";
string globPattern = "Hello*";
string regexPattern = "^Hello";
// Glob pattern matching
bool globMatch = TextFilter.IsMatch(text, globPattern, filterType: TextFilterType.Glob);
// Regular expression matching
bool regexMatch = TextFilter.IsMatch(text, regexPattern, filterType: TextFilterType.Regex);
// Fuzzy matching
bool fuzzyMatch = TextFilter.IsMatch(text, "Helo", filterType: TextFilterType.Fuzzy);The primary class for text filtering operations.
| Name | Return Type | Description |
|---|---|---|
IsMatch(string text, string filter, TextFilterType filterType = TextFilterType.Glob, TextFilterMatchOptions textFilterMatchOptions = TextFilterMatchOptions.ByWordAny, TextFilterCaseSensitivity caseSensitivity = TextFilterCaseSensitivity.CaseSensitive) |
bool |
Tests if the input text matches the specified filter |
IsMatch(string text, string filter, out int score, ...) |
bool |
As above, and also returns the fuzzy score (int.MinValue for glob and regex) |
Filter(IEnumerable<string> strings, string filter, TextFilterType filterType = TextFilterType.Glob, TextFilterMatchOptions textFilterMatchOptions = TextFilterMatchOptions.ByWordAny, TextFilterCaseSensitivity caseSensitivity = TextFilterCaseSensitivity.CaseSensitive) |
IEnumerable<string> |
Returns all strings that match the filter |
Filter<TItem>(IEnumerable<TItem> items, Func<TItem, string> keySelector, string filter, ...) |
IEnumerable<TItem> |
Returns all items whose key matches the filter |
Rank(IEnumerable<string> strings, string fuzzyFilter) |
IEnumerable<string> |
Returns the strings ranked by how well they fuzzy-match the filter |
Rank<TItem>(IEnumerable<TItem> items, Func<TItem, string> keySelector, string fuzzyFilter) |
IEnumerable<TItem> |
Returns the items ranked by how well their key fuzzy-matches the filter |
GetHint(TextFilterType filterType) |
string |
Returns a short description of the syntax a filter type accepts |
| Value | Description |
|---|---|
ByWholeString |
Match the entire string against the pattern |
ByWordAll |
Match all words in the pattern against the string |
ByWordAny |
Match any word in the pattern against the string (the default) |
| Value | Description |
|---|---|
Glob |
Use glob pattern matching (the default) |
Regex |
Use regular expression matching |
Fuzzy |
Use fuzzy matching |
| Value | Description |
|---|---|
CaseSensitive |
Uppercase and lowercase are distinct (the default) |
CaseInsensitive |
Uppercase and lowercase are equivalent, for glob and regex matching |
Contributions are welcome! For feature requests, bug reports, or questions, please open an issue on GitHub. If you would like to contribute code, please open a pull request with your changes.
This project is licensed under the MIT License - see the LICENSE file for details.
- DotNet.Glob for glob pattern matching.
- ktsu.FuzzySearch for fuzzy matching.