Pattern matching for .NET

Highly optimized.
Fast wildcard matching.

Match strings and character spans with * and ?. Choose direct WildcardMatch execution or the WildcardMatchRegex string engine, with reusable matchers, case options, and explicit timeouts.

4.24× the throughput of the next-fastest tested library for the reusable direct matcher in our question-mark benchmark. Compare the measured workloads.

NuGet package version Build and test status
  • .NET Standard 2.1 · .NET 10 / 11
  • No runtime package dependencies
  • LGPL-2.1
WILDCARD PATTERNCase-sensitive matching
report-??.txt
Two characters between the prefix and extension.
report-01.txtMATCH
report-aa.txtMATCH
report-1.txtNO MATCH
report-001.txtNO MATCH
EQUIVALENT REGEX^report-..\.txt$
Both engines share wildcard semantics. WildcardRegex exposes the equivalent anchored expression for inspection.

Two wildcard tokensStar for a sequence, question mark for one character

Reusable patternsRetain a pattern and match multiple strings

Regex controlsCase, culture, direction, and line handling

Portable package.NET Standard 2.1 with native .NET 10 and 11 targets

Pattern language

Small syntax.
Useful control.

Patterns use two operators. Every other character is literal, including dots, brackets, and regular-expression punctuation.

01 / Sequence

* → zero or more

report-*.txt matches report-.txt and report-summary.txt. Use stars at both ends for substring matching.

02 / Character

? → exactly one

report-??.txt requires two UTF-16 code units in that position. It matches report-01.txt.

03 / Literal

Punctuation stays literal

file[1].txt matches that literal filename. This is string matching: slashes have no special path semantics.

Patterns translate to ^…$. .NET permits $ before a final newline. Wildcards exclude \n unless Singleline is set.

Choose an API

The right lifetime
for your pattern.

Use the same wildcard syntax through extension methods, static calls, or an instance. Direct calls avoid Regex translation; instances retain pattern classification and case behavior.

01 / Convenient

Extension or static call

text.IsWildcardMatch(pattern) and WildcardMatch.IsMatch(text, pattern) match directly without Regex translation or per-match buffers.

02 / Repeated matches

Reusable instance

new WildcardMatch(pattern) retains its pattern and case behavior. Inspect WildcardRegex for a lazily generated equivalent expression.

03 / Regex execution

Compiled Regex instance

new WildcardMatchRegex(pattern, WildcardOptions.Compiled) compiles Regex execution. The direct engine accepts this flag without additional compilation.

Options: IgnoreCase, CultureInvariant, Singleline, Compiled, and RightToLeft. Combine flags with |.

Start matching

Install. Match.
Reuse.

Match strings and character spans. The package targets .NET Standard 2.1, .NET 10, and .NET 11. .NET 8 and 9 use its Standard assembly. .NET Framework is not supported. These examples use the Tedd namespace.

dotnet add package Tedd.WildcardMatch
Convenience API
using Tedd;

// Extension method.
bool first = "report-01.txt"
    .IsWildcardMatch("report-??.txt"); // true

// Static method, with case handling.
bool second = WildcardMatch.IsMatch(
    "REPORT-01.TXT",
    "report-??.txt",
    WildcardOptions.IgnoreCase |
    WildcardOptions.CultureInvariant); // true
Reusable pattern with a timeout
using System;
using Tedd;

var matcher = new WildcardMatch(
    "report-*.txt",
    WildcardOptions.CultureInvariant,
    TimeSpan.FromMilliseconds(100));

bool first = matcher.IsMatch("report-01.txt");
bool second = matcher.IsMatch("report-summary.txt");

// Generated regex: ^report-.*\.txt$
Console.WriteLine(matcher.WildcardRegex);
Borrow string, array, or stack-buffer slices
using System;
using Tedd;

ReadOnlySpan<char> input = "[report-01.txt]".AsSpan(1, 13);
ReadOnlySpan<char> pattern = "report-??.txt".AsSpan();

bool first = WildcardMatch.IsMatch(input, pattern);
bool second = input.IsWildcardMatch(pattern);
var matcher = new WildcardMatch(pattern); // Copies the pattern once.
bool third = matcher.IsMatch(input);

Static span calls borrow both slices. Reusable matchers borrow each input and own a copy of a span pattern. Ordinary matching avoids creating strings. Span<char> also supports the extension method; ReadOnlyMemory<char> callers use .Span. Keep buffers stable during each call. Default spans represent empty text. Timeout diagnostics materialize their text; .NET 11 vertical-tab normalization with numeric IgnorePatternWhitespace options uses stack or pooled scratch storage.

Bound execution for untrusted patterns.

The default timeout is infinite. Instance constructors accept a TimeSpan; a timeout raises RegexMatchTimeoutException.

API source ↗

Measured on .NET 10

Short strings.
Long strings.

Compare matching throughput across short inputs and strings over 1,000 characters. Select a short-string pattern to see literal, question-mark, and multi-star workloads. Higher bars mean faster matching.

Both engines receive identical string inputs: direct static and reused calls, plus Regex static, reused, and compiled calls. Reused instances are prepared before timing; static calls include their per-call setup.

Each graph includes every tested library and API. Full results, confidence intervals, and construction costs are available in the linked reports.

4–16 UTF-16 code units
Short strings · matching throughputQuestion marksPattern: report-??.txt · millions of matches/s
Tedd direct · reused
188.05
Tedd direct · static
52.62
DotNet.Glob
44.35
WildcardMatch
27.81
Tedd Regex · compiled
26.75
Tedd Regex · reused
12.05
FastWildcard
11.88
Tedd Regex · static
5.44

Reusable direct matcher: 4.24× the throughput of the next-fastest tested library on this workload.

Every input exceeds 1,000 UTF-16 code units
Long strings · matching throughputLong textPattern: *alpha*beta??*omega* · millions of matches/s
Tedd direct · reused
4.47
FastWildcard
3.81
Tedd direct · static
3.35
Tedd Regex · compiled
2.17
DotNet.Glob
0.14
WildcardMatch
0.07
Tedd Regex · reused
0.04
Tedd Regex · static
0.04

Reusable direct matcher: 1.17× the throughput of the next-fastest tested library on this workload.

Measured 2026-10-02 · AMD Ryzen 9 5950X · .NET 10 · three processes with optimized JIT. Reusable patterns are prepared before timing. Results depend on workload and API lifetime; full timings, intervals, allocations and configuration are linked below. Library source: 5043403.