pwnell
pwnell

Reputation: 171

How to perform a Regex replacement on one named capture group only?

If I have a varying regular expression that could look like any of the following patterns:

(.{2})(?<somedigit>\d+)(.{5})
(?<somedigit>\d+)(.{7})
(.{1})(?<somedigit>\d+)

and I want to replace the somedigit capture group with any number, and leave everything else untouched, how would I do that (say in C# or Java)?

For instance, say I have this text:

QB2-G456

and I use this regex:

(.{2})(?<somedigit>\d+)(.{5})

to match it, and say I want to replace the somedigit with 35, to get this final result:

QB35-G456

I know I can use this replacement text:

${1}35${2}

But the root of my question is that I do not know the format of my regular expression upfront. So I cannot hard code the capture group references for the text I do not want to change, as there could be different variations.

Since multiple numbers may be present I cannot just replace \d+ as I do not know whether the numbers are in the beginning or end or middle and whether other numbers are present further-on in the text.

Ideally I was hoping for something like:

new Regex("(.{2})(?<somedigit>\d+)(.{5})").ReplaceCaptureGroup("QB2-G456", "somedigit", "35")

and have everything pass through unmodified except the somedigit capture group that is replaced.

I searched for similar issues and only found solutions to where the regex is fixed and known, as already explained above.

Upvotes: 4

Views: 830

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626826

Here is how you can do it in C#:

 var str1 = "QB2-G456";
 var rx1 = new Regex(@"(.{2})(?<somedigit>\d+)(.{5})");
 var res = rx1.Replace(str1, m => m.Value.Replace(m.Groups["somedigit"].Value, "35"));
// Result: QB35-G35456

This will replace all occurrences of the "somedigit" group contents inside the string (i.e. QB2-G2456 will turn into QB35-G35456). To work around this, use a Regex.Replace(input, regex, repl, numOfReplacements) or this method:

public string ReplaceOnceAtIndex(string text, string search, string replace, int index)
{
    if (index < 0)
        return text;
    return text.Substring(0, index) + replace + text.Substring(index + search.Length);
}
// ... And thenin the caller ...
var res2 = rx1.Replace(str1, m => 
ReplaceOnceAtIndex(m.Value, m.Groups["somedigit"].Value, "35", m.Groups["somedigit"].Index));
// Result: QB35-G2456

Upvotes: 2

Related Questions