C# library for building .NET regular expressions with human-readable code.
Note: This is a fork of the original regex-builder by Yuriy Guts, updated to support .NET 9.
- Getting Started — Install and create your first pattern in 5 minutes
- Common Patterns — Copy-paste ready production patterns (email, URL, phone, etc.)
- API Guide — Full reference for the Fluent and Classic APIs
- NuGet Package — Official NuGet package page for RegexBuilder.NET9
- Installation
- Quick Start
- Real-World Example
- Documentation
- When to Use RegexBuilder
- Supported Features
- API Guide
- Advanced Usage
- Testing
- Development
- Contributing
- License
Just another day at the office—you write a .NET Regex like a boss, and suddenly realize that you need to declare a non-capturing group.
Is it (?:pattern)? Or (?=pattern) (positive lookahead)? Or (?<=pattern) (positive lookbehind)?
"Aaargh! Where's that Regex cheat sheet?!"
The Solution: Inspired by Expression Trees in .NET, RegexBuilder provides a more verbose but infinitely more human-readable way of declaring regular expressions using fluent, chainable C# code instead of cryptic regex patterns.
- Complex expressions that might be frequently changed
- Team environments where regex readability matters for maintainability
- Building patterns programmatically with conditional logic
- When clarity is worth the modest performance cost of constructing the Regex object
The following elements are supported:
- Quantifiers
- Character escapes
- Character classes
- Anchors (atomic zero-width assertions)
- Grouping constructs
- Backreference constructs
- Alternation constructs
- Inline options and comments
- Substitution patterns - for use with
Regex.Replace()
Install RegexBuilder.NET9 from NuGet using one of the following methods:
Via .NET CLI:
dotnet add package RegexBuilder.NET9 --version 1.1.1Via PackageReference in .csproj:
<PackageReference Include="RegexBuilder.NET9" Version="1.1.1" />You can also view the package page on NuGet: RegexBuilder.NET9 on NuGet
Here's a simple example to get you started. Let's build a regex to match email addresses:
var emailRegex = RegexBuilder.Build(
RegexBuilder.Group(
"localPart",
RegexBuilder.CharacterSet(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore)
),
RegexBuilder.Literal("@"),
RegexBuilder.Group(
"domain",
RegexBuilder.Concatenate(
RegexBuilder.CharacterSet(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore),
RegexBuilder.Literal("."),
RegexBuilder.CharacterSet(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore)
)
)
);
var match = emailRegex.Match("[email protected]");
if (match.Success)
{
Console.WriteLine(match.Groups["localPart"].Value); // user
Console.WriteLine(match.Groups["domain"].Value); // example.com
}Use the Fluent PatternBuilder for concise, chainable pattern creation. The following builds the same email validator:
var emailPattern = RegexBuilder.Pattern()
.Start()
.CharacterSet("a-zA-Z0-9._%+-", 1, null)
.Literal("@")
.CharacterSet("a-zA-Z0-9.-", 1, null)
.Literal(".")
.Letters(2, 6)
.End()
.Build();
var emailRegex2 = RegexBuilder.Build(emailPattern);
Console.WriteLine(emailRegex2.IsMatch("[email protected]")); // TrueLet's build a regex to capture href attributes from HTML hyperlinks. Compare the traditional approach:
Traditional regex (hard to read):
Regex hrefRegex = new Regex(
"href\\s*=\\s*(?:[\"'](?<Target>[^\"']*)[\"']|(?<Target>\\S+))",
RegexOptions.IgnoreCase
);With RegexBuilder (self-documenting):
const string quotationMark = "\"";
Regex hrefRegex = RegexBuilder.Build(
RegexOptions.IgnoreCase,
RegexBuilder.Literal("href"),
RegexBuilder.MetaCharacter(RegexMetaChars.WhiteSpace, RegexQuantifier.ZeroOrMore),
RegexBuilder.Literal("="),
RegexBuilder.MetaCharacter(RegexMetaChars.WhiteSpace, RegexQuantifier.ZeroOrMore),
RegexBuilder.Alternate(
RegexBuilder.Concatenate(
RegexBuilder.NonEscapedLiteral(quotationMark),
RegexBuilder.Group(
"Target",
RegexBuilder.NegativeCharacterSet(quotationMark, RegexQuantifier.ZeroOrMore)
),
RegexBuilder.NonEscapedLiteral(quotationMark)
),
RegexBuilder.Group(
"Target",
RegexBuilder.MetaCharacter(RegexMetaChars.NonwhiteSpace, RegexQuantifier.OneOrMore)
)
)
);More examples can be found in CustomRegexTests.cs.
Full documentation (including Getting Started, Common Patterns, and API Guide) is available in the docs/ folder and on the generated site.
- Local docs:
docs/(opendocs/index.md) - Generated site: https://somenoe.github.io/RegexBuilder.NET9/
RegexBuilder now includes a Fluent Builder Pattern for composing complex regex patterns with improved ergonomics. The PatternBuilder class provides a chainable API for building patterns step-by-step.
// Build an ID pattern that matches either "ID-123" or "CODE-AB"
var pattern = RegexBuilder.Pattern()
.Start() // ^ anchor
.Literal("ID-")
.Digits(3, 5) // \d{3,5}
.Or(o => o.Literal("CODE-").Letters(2, 4)) // | CODE-[a-zA-Z]{2,4}
.End() // $ anchor
.Build();
var regex = RegexBuilder.Build(pattern);
Console.WriteLine(regex.IsMatch("ID-123")); // True
Console.WriteLine(regex.IsMatch("CODE-AB")); // TrueAnchors:
Start()- Add start-of-line anchor^End()- Add end-of-line anchor$
Patterns:
Literal(string)- Literal text (auto-escaped)Digits(min, max)- Digit pattern\dwith quantifiersLetters(min, max)- Letter pattern[a-zA-Z]with quantifiersWhitespace(min, max)- Whitespace pattern\swith quantifiersWordCharacter(min, max)- Word character pattern\wwith quantifiersAnyCharacter(min, max)- Any character pattern.with quantifiersCharacterSet(charset, min, max)- Custom character set with quantifiers
Grouping:
Group(action)- Capturing group(pattern)NonCapturingGroup(action)- Non-capturing group(?:pattern)
Operators:
Or(action)- Alternation with another pattern via builderOr(node)- Alternation with an existing RegexNodeOptional(action)- Optional patternpattern?
Common Patterns:
Email()- Email patternUrl()- URL patternPattern(node)- Add a custom RegexNode
// Phone number pattern: [+1-]555-123-4567
var phonePattern = RegexBuilder.Pattern()
.Optional(o => o.Literal("+1"))
.Optional(o => o.Literal("-"))
.Group(g => g.Digits(3)) // Area code
.Optional(o => o.Literal("-"))
.Group(g => g.Digits(3)) // Prefix
.Optional(o => o.Literal("-"))
.Group(g => g.Digits(4)) // Line number
.Build();
var regex = RegexBuilder.Build(phonePattern);
Console.WriteLine(regex.IsMatch("555-123-4567")); // True
Console.WriteLine(regex.IsMatch("+1-555-123-4567")); // True
Console.WriteLine(regex.IsMatch("5551234567")); // TrueRegexBuilder has 4 main classes you'll work with:
-
RegexBuilder- Factory class for building regex patterns- Static methods that produce and combine different parts of a regular expression
- Entry points:
RegexBuilder.Build(...)andRegexBuilder.Pattern()
-
PatternBuilder- Fluent builder for composing patterns- Chainable methods for building complex patterns
- Entry point:
RegexBuilder.Pattern()
-
RegexQuantifier- Produces quantifiers for regex parts- Properties like
ZeroOrMore,OneOrMore,Optional,ExactCount(n),Range(min, max), etc.
- Properties like
-
RegexMetaChars- Named constants for character classesWordCharacter,NonwordCharacter,WhiteSpace,NonwhiteSpace, etc.- More readable than memorizing
\w,\W,\s,\S
Start by calling RegexBuilder.Build() and pass the components you want to combine:
// Simple pattern
var pattern = RegexBuilder.Build(
RegexBuilder.Literal("prefix-"),
RegexBuilder.MetaCharacter(RegexMetaChars.Digit, RegexQuantifier.OneOrMore)
);
// Matches: "prefix-123", "prefix-42", etc.
// With options
var pattern = RegexBuilder.Build(
RegexOptions.IgnoreCase,
RegexBuilder.Literal("hello"),
RegexBuilder.Literal(" "),
RegexBuilder.Literal("world")
);// Capturing group
var pattern = RegexBuilder.Build(
RegexBuilder.Group("name",
RegexBuilder.MetaCharacter(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore)
)
);
// Non-capturing group
var pattern = RegexBuilder.Build(
RegexBuilder.NonCapturingGroup(
RegexBuilder.Alternate(
RegexBuilder.Literal("cat"),
RegexBuilder.Literal("dog")
)
)
);Use SubstitutionBuilder to create replacement patterns for Regex.Replace():
// Swap two words
var pattern = RegexBuilder.Build(
RegexBuilder.Group("word1", RegexBuilder.MetaCharacter(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore)),
RegexBuilder.Literal(" "),
RegexBuilder.Group("word2", RegexBuilder.MetaCharacter(RegexMetaChars.WordCharacter, RegexQuantifier.OneOrMore))
);
var replacement = SubstitutionBuilder.Build(
SubstitutionBuilder.Group("word2"),
SubstitutionBuilder.Literal(" "),
SubstitutionBuilder.Group("word1")
);
string result = pattern.Replace("hello world", replacement);
// result = "world hello"The SubstitutionBuilder class supports all .NET substitution constructs:
SubstitutionBuilder.Group(int)orGroup(string)- Reference captured groupsSubstitutionBuilder.WholeMatch()- Insert entire matched text ($&)SubstitutionBuilder.BeforeMatch()- Insert text before match ($`)SubstitutionBuilder.AfterMatch()- Insert text after match ($')SubstitutionBuilder.LastCapturedGroup()- Insert last captured group ($+)SubstitutionBuilder.EntireInput()- Insert entire input string ($_)SubstitutionBuilder.LiteralDollar()- Insert literal $ ($$)SubstitutionBuilder.Literal(string)- Insert literal text (auto-escapes $)
See SubstitutionBuilderTests.cs for more examples.
RegexBuilder uses MSTest for unit testing. The RegexBuilder.Tests project contains all unit tests.
Run tests from Visual Studio:
- Open the Test Explorer (Test > Test Explorer)
- Click "Run All Tests" or run specific test classes
Run tests from command line:
dotnet test src/RegexBuilder.slnxTest project structure:
RegexBuilder.Tests/- All unit test filesRegexBuilder.Examples/- Executable examples demonstrating all README code samples
Format code (requires Prettier and dotnet format):
make format
# or manually:
npx prettier --write .
dotnet format srcBuild the project:
dotnet build src/RegexBuilder.slnxPack as NuGet package:
dotnet pack src/RegexBuilder/RegexBuilder.csprojContributions are welcome! Please:
- Create a feature branch from
master - Add tests for any new functionality
- Run
make formatto format code - Submit a pull request with a clear description
The source code is licensed under The MIT License.