Five ways to get a pattern, one Pattern type
Build it, convert it, describe it, learn it or pick it from the library. Whichever way you start, you get the same immutable Pattern that matches, explains, proves and exports.
- Fluent builder
- From a regex
- Typed template
- Learn from examples
- Common patterns
Compose a pattern from named building blocks. Every call returns a new, immutable pattern. Learn more
Pattern semver = Pattern.With
.StartOfLine
.NamedGroup("major", Pattern.With.Digit.Repeat.OneOrMore)
.Literal(".")
.NamedGroup("minor", Pattern.With.Digit.Repeat.OneOrMore)
.Literal(".")
.NamedGroup("patch", Pattern.With.Digit.Repeat.OneOrMore)
.EndOfLine;
semver.ToString(); // ^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)$
semver.IsMatch("3.1.0"); // true
semver.IsMatch("3.1"); // false
Parse a regex you already have, then turn it into readable fluent C# you can keep in source control. Learn more
Pattern legacy = Pattern.FromRegex(@"^(?<area>\d{3})-(?<line>\d{4})$");
string code = legacy.ToFluentCode();
// Pattern.With
// .StartOfLine
// .NamedGroup("area", Pattern.With.Digit.Repeat.Times(3))
// .Literal("-")
// .NamedGroup("line", Pattern.With.Digit.Repeat.Times(4))
// .EndOfLine
Describe a line the way you would write an interpolated string. You get a typed parser and formatter. Learn more
public enum LogLevel { Debug, Info, Warn, Error }
public record LogLine(DateTime Date, LogLevel Level, string User, string Message);
Template<LogLine> log = Template.Of<LogLine>("{Date:yyyy-MM-dd} [{Level}] {User}: {Message}");
LogLine line = log.Parse("2026-11-02 [WARN] ahmad: disk at 91%");
// line.Level == LogLevel.Warn, line.User == "ahmad", line.Message == "disk at 91%"
string text = log.Format(line); // "2026-11-02 [Warn] ahmad: disk at 91%"
Give strings that must match and strings that must not. You get a readable, anchored pattern. Learn more
Pattern learned = Pattern.Learn(
match: new[] { "INV-2024-0001", "INV-2025-0420" },
reject: new[] { "INV-24-1", "inv-2024-0001" });
learned.ToString(); // ^INV-\d{4}-\d{4}$
learned.IsMatch("INV-2026-0007"); // true
Start from a ready-made pattern, and add checks that a regex alone cannot express. Learn more
CommonPatterns.Email().IsMatch("ahmad@example.com"); // true
CommonPatterns.IPv4(DigitMode.Ascii).IsMatch("192.168.0.1"); // true
ConstrainedPattern card = CommonPatterns.CreditCard().Must(Validators.Luhn, "Luhn checksum");
card.IsMatch("4111 1111 1111 1111"); // true
card.IsMatch("4111 1111 1111 1112"); // false: the shape is right, the checksum is not
More than a builder
Start with a readable pattern. Then prove it, harden it, test it and take it wherever your data lives, without rewriting it for each place.
Prove two patterns equal
Pattern.Compare decides equivalence, subset and overlap exactly. When two patterns differ, you get the shortest string that tells them apart.
Read the guide\d{3}right[0-9]{3}- Relation
ProperSuperset- Shortest counterexample
"00٠"left acceptsright rejects- Both accept
"000"
٠ is an Arabic-Indic zero: \d matches every Unicode decimal digit.
Optimize with proof
Optimize() rewrites cat|car|cab to ca[trb], then proves the result matches exactly the same strings.
Read the guideCatch ReDoS early
AnalyzeSafety() finds repetitions that backtrack exponentially, and can confirm each one with a timed attack.
Read the guideTyped extraction
Extract<T>() binds named groups straight onto records and classes, converting each value to its member type.
Read the guideChecked as you type
The bundled source generator and analyzers flag invalid patterns, ReDoS risks and group-name typos at build time.
Read the guideCoverage and test data
MeasureCoverage() shows the branches your tests never hit. GenerateMatching() and GenerateNonMatching() produce samples and near misses.
Read the guideRun it in the database
The same pattern becomes each database’s own regex, with the exact .NET meaning. The EF Core package runs it inside LINQ queries and CHECK constraints.
Read the guide| Dialect | SQL |
|---|---|
| PostgreSQL | Sku ~ '\A[A-Z]{3}-[0-9]{4}(?=\n?\Z)' |
| MySQL | REGEXP_LIKE(Sku, '(?-i)\\A[A-Z]{3}-[0-9]{4}(?=\\n?\\z)') |
| SQL Server 2025 | REGEXP_LIKE(Sku, N'\A[A-Z]{3}-[0-9]{4}\n?\z') |
| SQLite | Sku REGEXP '^[A-Z]{3}-[0-9]{4}$' |
Trace every match
Trace(input) shows which construct matched which text, or exactly where and why matching failed.
Read the guideOne pattern, every platform
ToJavaScript(), JSON Schema and TypeScript output keep the .NET meaning in browsers and API contracts.
Read the guideRedact personal data
Redactor.For(...) finds emails, phone numbers and other personal data in text, and masks each with the style you choose.
Read the guideInstall the core. Add only what you use.
All six packages ship together with one version number. Each companion library depends only on the core and the framework it plugs into.
Masterly.FluentRegexThe fluent builder, matching, extraction, templates, pattern algebra, optimizer, ReDoS analysis and export. Ships the source generator and analyzers.
Masterly.FluentRegex.EntityFrameworkCorePatterns in LINQ run as the database’s own regex, with proven index hints and CHECK constraints.
Masterly.FluentRegex.AspNetCoreRegister named patterns once and use them as route constraints, such as {id:pattern(sku)}.
Masterly.FluentRegex.Xunit[MatchingData] and [NonMatchingData] feed xUnit v3 theories with matches and near misses.
Masterly.FluentRegex.AIDescribe a pattern in plain language. Claude drafts it, and every draft is verified locally first.
Masterly.FluentRegex.ToolThe fluentregex .NET tool compares, optimizes, exports and scans a codebase for ReDoS in CI.
Write your first readable pattern in five minutes.
The Quick Start builds a pattern, tests it, extracts matches with named groups and explains it. The playground runs every feature in your browser.