Skip to main content

Overview

Masterly.FluentRegex is a library for building .NET regular expressions you can read. Instead of writing ^\d{3}-\d{4}$ by hand, you write Pattern.With.StartOfLine.Digit.Repeat.Times(3).Literal("-")... and the library writes the regex for you, escaping every special character along the way.

A pattern is more than a builder, though. The same immutable Pattern matches and extracts text, explains itself in plain English, proves whether two patterns accept the same strings, finds ReDoS risks, generates test data, and exports itself to JavaScript, JSON Schema and the regex dialects of five databases. Every call returns a new pattern, so building blocks are safe to share.

The core package targets .NET Standard 2.1, .NET 8 and .NET 10 and has no dependencies. It also ships a source generator and analyzers that check your patterns while you type. Five optional packages add Entity Framework Core, ASP.NET Core, xUnit, AI drafting and a command-line tool.

How it works​

Working with patterns has four stages. Most projects use the first two every day and reach for the last two when a pattern matters: when it guards input, runs in a database, or must behave the same in a browser. Select a stage to read its guide.

The packages​

All six packages ship together with one version number. Install the core first; add a companion package only when you use the framework it plugs into.

PackageWhat it addsTargets
Masterly.FluentRegexThe fluent builder, matching, extraction, templates, pattern algebra, optimizer, ReDoS analysis, export and SQL dialects, plus the bundled source generator and analyzers. No dependencies..NET Standard 2.1, .NET 8, .NET 10
Masterly.FluentRegex.EntityFrameworkCoreUseFluentRegex(): patterns in LINQ run as the database's own regex, with proven index hints and CHECK constraints..NET 8 (EF Core 8), .NET 10 (EF Core 10)
Masterly.FluentRegex.AspNetCoreAddFluentPatterns(...) and the pattern(name) route constraint..NET 8, .NET 10
Masterly.FluentRegex.Xunit[MatchingData] and [NonMatchingData] theory data for xUnit v3..NET 8, .NET 10
Masterly.FluentRegex.AIPatternAssistant, which drafts patterns from plain-language descriptions with Claude and verifies every draft locally..NET 8, .NET 10
Masterly.FluentRegex.ToolThe fluentregex .NET tool: compare, optimize, export, scan a codebase for ReDoS, and more..NET 8

See Installation for the install commands.

What's new in 3.1​

Version 3.1 can prove things about your patterns, learn them from examples, and take them beyond .NET into browsers, databases, tests and logs.

FeatureIn one line
Pattern algebraPattern.Compare(a, b) proves two patterns equivalent, or returns the shortest string that tells them apart.
Verified optimizerOptimize() rewrites cat|car|cab to ca[trb] and proves that nothing changed.
Typed templatesTemplate.Of<T>("{Date:yyyy-MM-dd} [{Level}] {Message}") parses and formats typed values.
Learning from examplesPattern.Learn(match, reject) infers a readable, anchored pattern.
Regex coverageMeasureCoverage(inputs) shows the branches and limits your tests never reach.
Property testingPatternProperty.ForMatching(...) finds and shrinks counterexamples to a property.
Semantic rules and PII redaction.Must(Validators.Luhn) adds checks a regex cannot express; Redactor masks personal data.
Export, SQL dialects and SQL LIKEJavaScript, JSON Schema, PostgreSQL, MySQL, MariaDB, SQL Server 2025 and SQLite, each with the exact .NET meaning.
Language factsGetLanguageFacts() proves length bounds and the prefix and suffix every match must have.
Backtracking profilerProfile(input) counts backtracking steps per construct.
StreamingMatchesAsync(stream) matches input of any size in constant memory.
UnicodeUnicode scripts, script-specific digits, graphemes, IgnoreDiacritics() and an ASCII digit mode.
Entity Framework Core, ASP.NET Core, xUnit, AI draftingFour new companion packages.
HighlightingHighlight(text, format) marks every match and group capture, as ANSI colors, encoded HTML or plain brackets.
Model validation[MatchesPattern(typeof(Patterns), nameof(Patterns.Sku))] validates DataAnnotations models (.NET 8 and .NET 10).
Pattern equalityPattern implements IEquatable<Pattern>, so patterns that render the same regex work as dictionary keys.
Debugger viewThe debugger shows a pattern as its regex. Expand it to see options, groups, an explanation and a ReDoS verdict.
Command-line toolEight new commands: compare, optimize, learn, profile, highlight, coverage, export and facts.
PlaygroundThe library running in your browser with WebAssembly, with shareable links.
InstallationNew .NET 10 targets. The net9.0 build is gone; .NET 9 apps use the .NET 8 build.

Three additions you will use every day​

Highlighting, value equality and the [MatchesPattern] attribute need no setup. They are part of the core package.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using Masterly.FluentRegex;

Pattern phone = Pattern.With
.Digit.Repeat.Times(3)
.Literal("-")
.Digit.Repeat.Times(4);

// Highlighting: mark every match
Console.WriteLine(phone.Highlight("Call 555-1234 or 555-9876", HighlightFormat.Brackets));
// prints: Call [555-1234] or [555-9876]
Console.WriteLine(phone.Highlight("Call 555-1234 <now>", HighlightFormat.Html));
// prints: Call <mark class="frx-match">555-1234</mark> &lt;now&gt;

// Equality: same regex, same options, same timeout
Pattern built = Pattern.With.Digit.Repeat.Times(3);
Pattern parsed = Pattern.With.RegEx(@"\d{3}");
Console.WriteLine(built.Equals(parsed)); // True
Console.WriteLine(built == parsed); // False

Dictionary<Pattern, string> names = new Dictionary<Pattern, string> { [built] = "three digits" };
Console.WriteLine(names[parsed]); // three digits

// DataAnnotations: validate a model property against a pattern
Order order = new Order { Sku = "ab-12" };
List<ValidationResult> results = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(order, new ValidationContext(order), results, validateAllProperties: true);
Console.WriteLine(isValid); // False
Console.WriteLine(results[0].ErrorMessage); // The field Sku does not match the required pattern.

public static class Patterns
{
public static Pattern Sku { get; } = Pattern.With
.StartOfLine
.UppercaseLetter.Repeat.Times(2)
.Literal("-")
.Digit.Repeat.Times(4)
.EndOfLine;
}

public sealed class Order
{
[MatchesPattern(typeof(Patterns), nameof(Patterns.Sku))]
public string? Sku { get; set; }
}
  • Highlight defaults to HighlightFormat.Ansi, for terminals. Html encodes all of the text, so <now> becomes &lt;now&gt; and the output is safe to put on a page. Brackets is plain text for tests and logs. See Highlighting.
  • Two patterns are equal when they render the same regex text with the same options and timeout, however you built them. The == operator keeps reference semantics, so use Equals. See Core Concepts.
  • [MatchesPattern] takes the type and the name of a public static property, field or parameterless method that returns a Pattern or a ConstrainedPattern. The whole value must match. Null and empty strings are valid, so add [Required] to reject them. The attribute is not in the .NET Standard 2.1 build. See Semantic Rules.
See a pattern in the debugger

You do not need any code for the debugger view. Hover over a Pattern variable to see its regex, then expand it. See Validation and Debugging.

Coming from 2.x? Version 3.0 made patterns immutable. Read Upgrading from 2.x before you update.

What you can do​

Contributing and building from source​

Contributions are welcome. For a major change, please open an issue on GitHub first to discuss what you would like to change.

What you need​

ToolWhy
.NET 10 SDKBuilds every target: .NET Standard 2.1, .NET 8 and .NET 10.
.NET 8 runtimeRuns the tests on .NET 8. The .NET 8 SDK includes it.
Node.js 20 or laterRuns the documentation site.
Docker (optional)Runs the Entity Framework Core tests against real database servers.

Building and testing​

git clone https://github.com/a7mdfre7at/Masterly.FluentRegex.git
cd Masterly.FluentRegex
dotnet test # .NET 8 and .NET 10
dotnet run --project samples/Masterly.FluentRegex.Showcase # a tour of every feature
  • dotnet test builds the solution and runs every test project on .NET 8 and .NET 10. The playground tests run on .NET 10 only.
  • The tests in test/Masterly.FluentRegex.EntityFrameworkCore.Tests/Containers start PostgreSQL, MySQL, MariaDB and SQL Server 2025 in Docker. When Docker cannot be reached, they are skipped, not failed. To leave them out, run dotnet test --filter "FullyQualifiedName!~Containers", as the build workflow does.
  • The showcase is a console app that references the library project, so it shows your local changes. It prints one numbered section per feature, starting with 1. Immutable building blocks and operators.
  • The build workflow also scans the repository for risky regex literals. Run the same check with dotnet run --project tools/Masterly.FluentRegex.Cli -- scan . --fail-on high. See Command-Line Tool.
  • A build does not create packages. Run dotnet pack -c Release to create the .nupkg files.

Running the documentation site​

The site you are reading lives in the website folder. It is a Docusaurus site:

cd website
npm ci
npm start
  • npm start serves the site at http://localhost:3000/Masterly.FluentRegex/ and reloads a page when you save its file in website/docs.
  • npm run build builds the static site, as the docs workflow does. It fails on any broken link or anchor, so run it before you open a pull request that changes the docs.
  • The browser playground is a separate .NET project in playground/. See Playground to run it locally.

Where to go next​