Replace named group in regex with value

Another edited version of the original method by @user1817787, this one supports multiple instances of the named group (also includes similar fix to the one @Justin posted (returns result using {match.Index, match.Length} instead of {0, input.Length})):

public static string ReplaceNamedGroup(
    string input, string groupName, string replacement, Match match)
{
    var sb = new StringBuilder(input);
    var matchStart = match.Index;
    var matchLength = match.Length;

    var captures = match.Groups[groupName].Captures.OfType<Capture>()
        .OrderByDescending(c => c.Index);

    foreach (var capt in captures)
    {
        if (capt == null)
            continue;

        matchLength += replacement.Length - capt.Length;

        sb.Remove(capt.Index, capt.Length);
        sb.Insert(capt.Index, replacement);
    }

    var end = matchStart + matchLength;
    sb.Remove(end, sb.Length - end);
    sb.Remove(0, matchStart);

    return sb.ToString();
}

There was a problem in user1817787 answer and I had to make a modification to the ReplaceNamedGroup function as follows.

private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m)
{
    string capture = m.Value;
    capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length);
    capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement);
    return capture;
}

Yes, it is possible:

public static class RegexExtensions
{
    public static string Replace(this string input, Regex regex, string groupName, string replacement)
    {
        return regex.Replace(input, m =>
        {
            return ReplaceNamedGroup(input, groupName, replacement, m);
        });
    }

    private static string ReplaceNamedGroup(string input, string groupName, string replacement, Match m)
    {
        string capture = m.Value;
        capture = capture.Remove(m.Groups[groupName].Index - m.Index, m.Groups[groupName].Length);
        capture = capture.Insert(m.Groups[groupName].Index - m.Index, replacement);
        return capture;
    }
}

Usage:

Regex regex = new Regex("^(?<PREFIX>abc_)(?<ID>[0-9]+)(?<POSTFIX>_def)$");

string oldValue = "abc_123_def";
var result = oldValue.Replace(regex, "ID", "456");

Result is: abc_456_def


No, it's not possible to use a regular expression without providing input. It has to have something to work with, the pattern can not add any data to the result, everything has to come from the input or the replacement.

Intead of using String.Format, you can use a look behind and a look ahead to specify the part between "abc_" and "_def", and replace it:

string result = Regex.Replace(input, @"(?<=abc_)\d+(?=_def)", "999");

Tags:

C#

Regex