Regular expressions are powerful, but let’s be honest — they’re also notoriously difficult to read and maintain. What does ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ mean at first glance? If you're like most developers, you'll need a moment (or several) to decode it.
Enter Rejigs — a fluent C# library that transforms the cryptic world of regex into readable, maintainable code. Instead of wrestling with arcane symbols, you can now build regular expressions using intuitive, English-like methods.
Traditional regular expressions suffer from several issues:
- Readability: Complex patterns are nearly impossible to understand without deep regex knowledge
- Maintainability: Modifying existing patterns is error-prone and time-consuming
- Learning Curve: New team members struggle with regex syntax
- Documentation: Patterns require extensive comments to explain their purpose
Consider this email validation regex:
^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$What does it do? How would you modify it to allow underscores in the domain? These simple questions become complex puzzles.
Rejigs transforms the same email validation into this:
var emailRegex =Rejigs.Create()
.AtStart()
.OneOrMore(r => r.AnyLetterOrDigit().Or().AnyOf("._%+-"))
.Text("@")
.OneOrMore(r => r.AnyLetterOrDigit().Or().AnyOf(".-"))
.Text(".")
.AnyLetterOrDigit().AtLeast(2)
.AtEnd()
.Build();
Now the intent is crystal clear: start at the beginning, match one or more valid email characters, then an @ symbol, then domain characters, then a period, then at least two letters for the top-level domain, and end there.
1. Text Matching and Anchoring
// Match exact textRejigs.Create().Text("hello").Build(); // Matches "hello"// Anchor to start/end
Rejigs.Create()
.AtStart()
.Text("Hello")
.AtEnd()
.Build(); // Matches exactly "Hello", nothing more or less
// Word boundaries
Rejigs.Create()
.AtWordBoundary()
.Text("cat")
.AtWordBoundary()
.Build(); // Matches "cat" as a whole word, not as part of "category"
2. Character Classes Made Simple
Instead of memorizing \d, \w, \s and their counterparts:
var regex =Rejigs.Create()
.AnyDigit() // \d
.AnyLetterOrDigit() // \w
.AnySpace() // \s
.AnyCharacter() // .
.AnyNonDigit() // \D
.Build();// Character sets and ranges
var phoneRegex =
Rejigs.Create()
.AnyOf("0123456789-() ") // Custom character set
.AnyInRange('A', 'Z') // Character range
.AnyExcept("@#$") // Everything except these
.Build();
3. Quantifiers That Make Sense
var passwordRegex =Rejigs.Create()
.AtStart()
.AnyLetterOrDigit().AtLeast(8) // At least 8 characters
.AnyDigit().Exactly(2) // Exactly 2 digits
.AnyOf("!@#$").Between(1, 3) // 1-3 special characters
.AtEnd()
.Build();// Optional elements
var urlRegex =
Rejigs.Create()
.AtStart()
.Optional("http://") // Optional protocol
.Optional(r => r.Text("www.")) // Optional www
.OneOrMore(r => r.AnyLetterOrDigit()) // Domain name
.Text(".")
.AnyLetterOrDigit()
.AtLeast(2)
.AtEnd()
.Build();
4. Grouping and Alternation
// Either/or patternsvar fileExtension =
Rejigs.Create()
.Text(".")
.Either(
r => r.Text("jpg"),
r => r.Text("png"),
r => r.Text("gif")
)
.Build();// Complex grouping
var phoneNumber =
Rejigs.Create()
.Optional(r => r.Text("+").AnyDigit().Between(1, 3)) // Country code
.Grouping(r => r.AnyDigit().Exactly(3)) // Area code
.Optional("-")
.Grouping(r => r.AnyDigit().Exactly(3)) // Exchange
.Optional("-")
.Grouping(r => r.AnyDigit().Exactly(4)) // Number
.Build();
Parsing Log Files
var logEntryRegex =Rejigs.Create()
.AtStart()
.Grouping(r => r.AnyDigit().Exactly(4)) // Year
.Text("-")
.Grouping(r => r.AnyDigit().Exactly(2)) // Month
.Text("-")
.Grouping(r => r.AnyDigit().Exactly(2)) // Day
.AnySpace().OneOrMore() // Whitespace
.Grouping(r => r.AnyExcept(" ").OneOrMore()) // Log level
.AnySpace().OneOrMore()
.Grouping(r => r.AnyCharacter().ZeroOrMore()) // Message
.Build();
URL Validation
var urlRegex =Rejigs.Create()
.AtStart()
.Either(
r => r.Text("http://"),
r => r.Text("https://")
)
.Optional(r => r.Text("www."))
.OneOrMore(r => r.AnyLetterOrDigit().Or().AnyOf(".-"))
.Optional(r => r.Text(":").AnyDigit().OneOrMore()) // Port
.Optional(r => r.Text("/").AnyCharacter().ZeroOrMore()) // Path
.AtEnd()
.Build();
Raw Patterns When Needed
Sometimes you need the full power of regex. Rejigs doesn’t restrict you:
var advancedRegex =Rejigs.Create()
.Text("start")
.Pattern(@"(?=.*\d)(?=.*[a-z])(?=.*[A-Z])") // Lookaheads
.Text("end")
.Build();
Regex Options Support
var caseInsensitiveRegex =Rejigs.Create()
.Text("Hello")
.Build(RegexOptions.IgnoreCase | RegexOptions.Multiline);
1. Self-Documenting Code
Your regex patterns become their own documentation. New team members can understand what a pattern does just by reading the method calls.
2. Easier Maintenance
Need to modify a pattern? Change the fluent method calls instead of deciphering regex syntax. Want to make email domains case-insensitive? Add .Build(RegexOptions.IgnoreCase).
3. Reduced Errors
The fluent API guides you toward correct patterns. No more wondering if you need to escape that dot or whether you have the right number of backslashes.
4. Better Testing
You can build patterns incrementally and test each part:
var basePattern = Rejigs.Create().AtStart().Text("user");var withDomain = basePattern.Text("@").OneOrMore(r => r.AnyLetterOrDigit());
var complete = withDomain.Text(".com").AtEnd();// Test each stage
Assert.IsTrue(basePattern.Build().IsMatch("[email protected]"));
Assert.IsTrue(withDomain.Build().IsMatch("[email protected]"));
Assert.IsTrue(complete.Build().IsMatch("[email protected]"));
5. Learning Tool
Rejigs helps developers learn regex concepts without getting lost in syntax. You can always call .Expression to see the generated regex pattern and learn how traditional regex works.
Installation
dotnet add package RejigsBasic Usage
using Rejigs;// Create a simple patternvar pattern =
Rejigs.Create()
.Text("Hello")
.AnySpace()
.Text("World")
.Build();
// Use it like any Regex
bool matches = pattern.IsMatch("Hello World");
string result = pattern.Replace("Hello World", "Hi Earth");
Rejigs generates standard .NET Regex objects, so runtime performance is identical to hand-written regex patterns. The only overhead is during pattern construction, which typically happens once during application startup.
For frequently used patterns, consider caching the built Regex object:
public static class CommonPatterns{
public static readonly Regex Email =
Rejigs.Create()
.AtStart()
.OneOrMore(r => r.AnyLetterOrDigit().Or().AnyOf("._%+-"))
.Text("@")
.OneOrMore(r => r.AnyLetterOrDigit().Or().AnyOf(".-"))
.Text(".")
.AnyLetterOrDigit().AtLeast(2)
.AtEnd()
.Build();
}
Perfect for:
- Complex validation patterns
- Data parsing and extraction
- Pattern matching in business logic
- Teams with mixed regex experience levels
- Applications requiring maintainable text processing
Consider alternatives when:
- You need maximum performance for simple patterns
- Working with regex experts who prefer traditional syntax
- Building very simple patterns (like single-character matches)
Regular expressions don’t have to be cryptic. Rejigs brings clarity to pattern matching, making your code more readable, maintainable, and accessible to your entire team.
Whether you’re validating user input, parsing log files, or extracting data from text, Rejigs helps you express your intent clearly while leveraging the full power of .NET’s regex engine.
Try Rejigs today and transform your regex patterns from mysterious hieroglyphs into readable, maintainable code that your future self (and your teammates) will thank you for.
.png)

![AI and Cybersecurity: Dan Boneh Interviews Sam Altman [video]](https://www.youtube.com/img/desktop/supported_browsers/firefox.png)
