This tool runs entirely in your browser. Nothing you paste is uploaded.
How you can check →.NET & PowerShell regex tester — System.Text.RegularExpressions rules, including the group-numbering quirk
Ships in: C#, F#, VB.NET, PowerShell
Want to test your own pattern under .NET / PowerShell (Regex)? Open the regex tester with this flavor already selected.
Open the regex tester — .NET / PowerShell (Regex) →System.Text.RegularExpressions is the one engine underneath C#, F#, VB.NET regex code and PowerShell's -match, -replace and Select-String — one implementation, several front doors, and one group-numbering rule that is different enough from every other flavor here to be worth its own paragraph before anything else.
Unnamed capturing groups are numbered first, in left-to-right source order — and named groups are numbered afterward, in their own left-to-right order, not interleaved by position the way Perl-family engines number them. (\d)(?<x>\w)(\d) puts the named group x at index 3, not 2, because both unnamed groups claim indices 1 and 2 first. A $2 written with a PCRE2 or JavaScript mental model, used against a .NET Match.Groups collection or a PowerShell $Matches array, silently reads the wrong capture — and it looks correct until the input changes shape and the group that used to be empty starts mattering.
.NET is also the one flavor here that allows duplicate group names outright — the same name reused for two different capturing groups in one pattern compiles without complaint, where PCRE2 rejects it unless the (?J) modifier is set and most other flavors reject it unconditionally. This is occasionally useful for alternation branches that want the "same" named capture regardless of which branch matched, but it's also a silent footgun if it happens by accident in a long pattern.
\d, \w and \s are Unicode-aware by default here, matching Python's default rather than JavaScript's or Java's ASCII-only one — RegexOptions.ECMAScript reverts them to ASCII-only and additionally restricts the rest of the pattern's syntax to an ECMAScript-compatible subset, which is the specific option name to reach for if you need .NET regex behavior to match JavaScript's rather than assume it already does.
PowerShell adds its own layer on top of the engine itself: the shell's own quoting rules run before .NET ever sees the pattern. A double-quoted PowerShell string interpolates $ — so a replacement template containing $1 written in double quotes gets the $1 eaten by PowerShell's own string interpolation before -replace ever receives it, silently turning your intended backreference into whatever $1 happens to resolve to as a PowerShell variable (usually nothing). Single-quoting the pattern and replacement string, or using a here-string, is the fix, and it's the single most common reason a -replace pattern that looks syntactically correct produces the wrong output.
Lookbehind here is unbounded-width, the same permissive rule Java and modern JavaScript use, so a pattern like (?<=\d+)abc that would fail to compile under Python or PCRE2's fixed-width restriction works fine in .NET without modification — one of the few places porting a pattern into .NET from a stricter flavor requires no rewriting at all.
.NET also has its own free-spacing mode, RegexOptions.IgnorePatternWhitespace (the x letter here), working the same way it does in PCRE2, Python and Java: unescaped whitespace and # comments inside the pattern are ignored, letting a long pattern be laid out and annotated field by field. Combined with C#'s verbatim string literals — @"\d+" needs no backslash-doubling the way a normal "\\d+" string does — a well-formatted .NET pattern in source code can be genuinely more readable than the equivalent single-line pattern in most other languages, at the cost of one more flag to remember to set consistently between where the pattern is written and where it's tested.
For PowerShell specifically, it's worth testing both directions of a pattern separately: -match (and the case-insensitive-by-default -match, with -cmatch for case-sensitive) populates the automatic $Matches variable as a hashtable keyed by group number and name, while Select-String is built for scanning files or piped text and returns richer MatchInfo objects with filename and line-number context attached. Both run the identical .NET engine underneath, so a pattern that's right for one is right for the other — the difference is entirely in what PowerShell hands back to you afterward, not in what matched.
.NET / PowerShell (Regex) quirks, at a glance
The same facts this tool's engine implements and tests against — not a separate, unverified summary.
- Unnamed capturing groups are numbered first, left to right; named groups are numbered afterward, in their own left-to-right order — (\d)(?<x>\w)(\d) puts x at group 3, not 2.
- Duplicate group names are allowed, unlike almost every other flavor here.
- RegexOptions.ECMAScript reverts \d/\w/\s to ASCII, which is the opposite of the Unicode-by-default the rest of .NET uses.
A worked example: PowerShell
Extracting a date like 2026-08-22 — ^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$.
$pattern = '^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$'
$input -match $pattern
Single quotes are deliberate: PowerShell's double-quoted strings interpolate $1, $matches, etc. before the regex engine ever sees the pattern, which silently corrupts it.
Frequently asked questions
- Why is $2 capturing the wrong group in my PowerShell -replace?
- In .NET, named groups are numbered AFTER every unnamed group in the pattern, not interleaved by source position — (\d)(?<x>\w)(\d) puts the named group at index 3, not 2. A replacement template written assuming Perl-style interleaved numbering will read the wrong capture.
- Why did my $1 backreference not work in PowerShell -replace?
- PowerShell interpolates $ inside double-quoted strings before .NET's regex engine ever sees them, so "$1" in a double-quoted replacement string is consumed by PowerShell itself. Single-quote the pattern and replacement, or use a single-quoted here-string, to pass $1 through intact.
- Are \d and \w Unicode-aware in .NET?
- Yes, by default — matching Python's default rather than JavaScript's or Java's ASCII-only default. RegexOptions.ECMAScript reverts \d/\w/\s to ASCII and restricts the rest of the syntax to an ECMAScript-compatible subset.
- Can two capturing groups share the same name in .NET?
- Yes — unlike almost every other flavor on this page, .NET allows duplicate group names in one pattern without any special modifier.
Other flavors
ECMAScript RegExp, exactly as your browser or Node runs it
the engine behind PHP's preg_* and most Apache/nginx rewrite rules
re module rules, Unicode-by-default, 3.11+ possessive quantifiers
java.util.regex rules for Java, Kotlin, Scala and Android
RE2 rules, including why lookaround and backreferences don't compile
POSIX ERE and leftmost-longest matching, not leftmost-first
POSIX BRE, where ( ) and { } are literal and \( \) \{ \} do the work