ktsu.FuzzySearch
1.3.12
Prefix Reserved
dotnet add package ktsu.FuzzySearch --version 1.3.12
NuGet\Install-Package ktsu.FuzzySearch -Version 1.3.12
<PackageReference Include="ktsu.FuzzySearch" Version="1.3.12" />
<PackageVersion Include="ktsu.FuzzySearch" Version="1.3.12" />
<PackageReference Include="ktsu.FuzzySearch" />
paket add ktsu.FuzzySearch --version 1.3.12
#r "nuget: ktsu.FuzzySearch, 1.3.12"
#:package ktsu.FuzzySearch@1.3.12
#addin nuget:?package=ktsu.FuzzySearch&version=1.3.12
#tool nuget:?package=ktsu.FuzzySearch&version=1.3.12
ktsu.FuzzySearch
A lightweight .NET library that provides fuzzy string matching capabilities, allowing for approximate string matching with intelligent scoring.
Introduction
FuzzySearch is a .NET library that provides fuzzy string matching capabilities with intelligent scoring. It's perfect for implementing search-as-you-type features, command palettes, or any application requiring flexible string matching.
The whole library is one static class, Fuzzy, with two Contains overloads: one that answers whether a subject matches a pattern, and one that also hands back a score you can rank by.
Features
- Subsequence Matching: Match a subject against a pattern whose characters appear in order but not necessarily together
- Intelligent Scoring: Rank matches by quality with a scoring algorithm that rewards adjacent matches, matches after separators, and matches at camelCase boundaries
- Case Insensitive: Matching always ignores case; there is no case-sensitive mode
- Unicode Aware: Input is normalized to NFC and compared one codepoint at a time, so surrogate pairs match as a whole
- Span Based: Takes
ReadOnlySpan<char>, and allocates nothing for ASCII input - Lightweight: Minimal dependencies, focused on performance
- Well-tested: Comprehensive test suite ensuring reliability
Installation
Package Manager Console
Install-Package ktsu.FuzzySearch
.NET CLI
dotnet add package ktsu.FuzzySearch
Package Reference
<PackageReference Include="ktsu.FuzzySearch" Version="x.y.z" />
Usage Examples
Basic Matching
The simplest way to check if a string contains characters from a pattern in sequence:
using ktsu.FuzzySearch;
class Program
{
static void Main()
{
string text = "Hello World";
string pattern = "hlo";
bool isMatch = Fuzzy.Contains(text, pattern); // Returns true
}
}
Matching with Scoring
The second overload also reports a score, so you can tell a good match from a barely-there one:
using ktsu.FuzzySearch;
class Program
{
static void Main()
{
string text = "Hello World";
string pattern = "hlo";
bool isMatch = Fuzzy.Contains(text, pattern, out int score);
Console.WriteLine($"Is match: {isMatch}"); // True
Console.WriteLine($"Score: {score}"); // Higher is better
}
}
The score is an unbounded int, not a normalized ratio. It is only meaningful when comparing candidates against the same pattern, and it is reported whether or not the whole pattern was found — a near miss still scores. Use the return value to decide whether it matched at all, and the score to order the matches.
Ranking a Collection
There is no built-in filter method. Ranking a collection is a Contains call per candidate:
using ktsu.FuzzySearch;
class Program
{
static void Main()
{
string[] items =
[
"AppDataStorage",
"Application Settings",
"Data Store",
"File System",
"Storage Provider",
];
string pattern = "stor";
List<(string Item, int Score)> matches = [];
foreach (string item in items)
{
if (Fuzzy.Contains(item, pattern, out int score))
{
matches.Add((item, score));
}
}
foreach ((string item, int score) in matches.OrderByDescending(match => match.Score))
{
Console.WriteLine($"{item} (Score: {score})");
}
// Storage Provider (Score: 15)
// Data Store (Score: 14)
// AppDataStorage (Score: 10)
}
}
Matching Against Objects
The same shape works for objects — project each one to the text you want matched:
using ktsu.FuzzySearch;
class Program
{
sealed class FileItem
{
public required string Name { get; init; }
public required string Path { get; init; }
}
static void Main()
{
FileItem[] files =
[
new() { Name = "Document.pdf", Path = "/documents/" },
new() { Name = "Presentation.pptx", Path = "/presentations/" },
new() { Name = "Spreadsheet.xlsx", Path = "/spreadsheets/" },
];
string pattern = "doc";
foreach (FileItem file in files)
{
if (Fuzzy.Contains(file.Name, pattern, out int score))
{
Console.WriteLine($"{file.Name} (Score: {score})");
}
}
}
}
API Reference
Fuzzy Static Class
Fuzzy is the library's entire public surface. It is a static class with two methods, both overloads of Contains.
Methods
| Name | Parameters | Return Type | Description |
|---|---|---|---|
Contains |
ReadOnlySpan<char> subject, ReadOnlySpan<char> pattern |
bool |
Whether subject contains every character of pattern, in order |
Contains |
ReadOnlySpan<char> subject, ReadOnlySpan<char> pattern, out int outScore |
bool |
The same answer, plus a match-quality score |
Both overloads take ReadOnlySpan<char>, so a string argument is passed straight through by the compiler's implicit conversion — there is no separate string overload to look for.
Behaviour
- Case is always ignored. There is no option to make matching case-sensitive.
- An empty pattern matches any non-empty subject, and scores
0. An empty subject never matches. - Scores are unbounded
ints, comparable only within a single pattern.outScoreis set even when the method returnsfalse. - Input is normalized to NFC before comparison, so precomposed and decomposed text match. This relies on the runtime's globalization data: under
InvariantGlobalization,string.Normalizeis a no-op and the two forms will not match. - Comparison advances one codepoint at a time, so a surrogate pair matches only as a whole and a lone surrogate cannot match half of an unrelated character.
Scoring
| Rule | Effect |
|---|---|
| Match adjacent to the previous match | +5 |
Match after a _ or space separator |
+10 |
| Match at a camelCase boundary | +10 |
| Each unmatched character | -1 |
| Unmatched characters before the first match | -1 each, capped at -5 |
Contributing
Contributions are welcome! Here's how you can help:
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Please make sure to update tests as appropriate and adhere to the existing coding style.
License
This project is licensed under the MIT License - see the LICENSE.md file for details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
- System.Threading.Tasks.Extensions (>= 4.6.3)
-
.NETStandard 2.1
- No dependencies.
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (3)
Showing the top 3 NuGet packages that depend on ktsu.FuzzySearch:
| Package | Downloads |
|---|---|
|
ktsu.TextFilter
A library providing methods for matching and filtering text. It supports glob patterns, regular expressions, and fuzzy matching. |
|
|
ktsu.ImGuiWidgets
A library of custom widgets using ImGui.NET and utilities to enhance ImGui-based applications. |
|
|
ktsu.Frontmatter
A .NET library for processing and manipulating YAML frontmatter in markdown files. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.3.12 | 82 | 9/24/2026 |
| 1.3.11 | 162 | 9/23/2026 |
| 1.3.10 | 293 | 9/22/2026 |
| 1.3.9 | 541 | 9/22/2026 |
| 1.3.8 | 115 | 9/21/2026 |
| 1.3.7 | 629 | 9/18/2026 |
| 1.3.6 | 528 | 9/17/2026 |
| 1.3.5 | 630 | 9/17/2026 |
| 1.3.4 | 113 | 9/16/2026 |
| 1.3.3 | 422 | 9/16/2026 |
| 1.3.2 | 618 | 9/14/2026 |
| 1.3.1 | 792 | 9/14/2026 |
| 1.3.0 | 210 | 9/13/2026 |
| 1.2.40 | 119 | 9/11/2026 |
| 1.2.39 | 4,414 | 9/3/2026 |
| 1.2.38 | 1,525 | 8/26/2026 |
| 1.2.37 | 1,246 | 8/21/2026 |
| 1.2.36 | 488 | 8/20/2026 |
| 1.2.35 | 684 | 8/19/2026 |
| 1.2.34 | 160 | 8/18/2026 |
## v1.3.12 (patch)
Changes since v1.3.11:
- Bump the ktsu group with 9 updates ([@dependabot[bot]](https://github.com/dependabot[bot]))