Coder Perfect

Regex is only used to replace a few groups.


Let’s pretend I’ve got the following regex:


and I want to replace Group 1 (d+) with AA using C#, to get:


I’m now replacing it with:

var text = "example-123-example";
var pattern = @"-(\d+)-";
var replaced = Regex.Replace(text, pattern, "-AA-"); 

But this bothers me since, if I alter the pattern to match _(d+)_ instead, I’ll have to update the replacement string to _AA_ as well, which violates the DRY principle.

I’m looking for anything along the lines of:

Keep the matched text the same, but replace Group 1 with this text and Group 2 with another…

That was merely an example. I’m just searching for a generic technique to accomplish what I’ve stated previously.

It should be suitable for:

any(d+)additional text and any pattern you can think of

I only want to replace the groupings and leave the rest of the match alone.

Asked by Oscar Mederos

Solution #1

A good idea could be to encapsulate everything inside groups, no matter if need to identify them or not. That way you can use them in your replacement string. For example:

var pattern = @"(-)(\d+)(-)";
var replaced = Regex.Replace(text, pattern, "$1AA$3"); 

Alternatively, you can use a MatchEvaluator:

var replaced = Regex.Replace(text, pattern, m => m.Groups[1].Value + "AA" + m.Groups[3].Value);

Another, but more clumsy option is to use a lookbehind/lookahead:


Answered by bluepnume

Solution #2

Lookahead and lookbehind can be used to accomplish this:

var pattern = @"(?<=-)\d+(?=-)";
var replaced = Regex.Replace(text, pattern, "AA"); 

Answered by LukeH

Solution #3

I had a need for this as well, therefore I wrote the following extension method:

public static class RegexExtensions
    public static string ReplaceGroup(
        this Regex regex, string input, string groupName, string replacement)
        return regex.Replace(
            m =>
                var group = m.Groups[groupName];
                var sb = new StringBuilder();
                var previousCaptureEnd = 0;
                foreach (var capture in group.Captures.Cast<Capture>())
                    var currentCaptureEnd =
                        capture.Index + capture.Length - m.Index;
                    var currentCaptureLength =
                        capture.Index - m.Index - previousCaptureEnd;
                            previousCaptureEnd, currentCaptureLength));
                    previousCaptureEnd = currentCaptureEnd;

                return sb.ToString();


var input = @"[assembly: AssemblyFileVersion("""")][assembly: AssemblyFileVersion("""")]";
var regex = new Regex(@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)");

var result = regex.ReplaceGroup(input , "version", "1.2.3");


[assembly: AssemblyFileVersion("1.2.3")][assembly: AssemblyFileVersion("1.2.3")]

Answered by Daniel Hilgarth

Solution #4

You can use the Group Index and Length properties of a matched group if you don’t want to update your pattern.

var text = "example-123-example";
var pattern = @"-(\d+)-";
var regex = new RegEx(pattern);
var match = regex.Match(text);

var firstPart = text.Substring(0,match.Groups[1].Index);    
var secondPart = text.Substring(match.Groups[1].Index + match.Groups[1].Length);
var fullReplace = firstPart + "AA" + secondPart;

Answered by Dick Verweij

Solution #5

Here’s another simple solution that won’t require you to change your design.

        var text = "example-123-example";
        var pattern = @"-(\d+)-";

        var replaced = Regex.Replace(text, pattern, (_match) =>
            Group group = _match.Groups[1];
            string replace = "AA";
            return String.Format("{0}{1}{2}", _match.Value.Substring(0, group.Index - _match.Index), replace, _match.Value.Substring(group.Index - _match.Index + group.Length));

Answered by curlyhairedgenius

Post is based on