Problem
Let’s pretend I’ve got the following regex:
-(\d+)-
and I want to replace Group 1 (d+) with AA using C#, to get:
-AA-
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:
(?<=-)(\d+)(?=-)
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(
input,
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;
sb.Append(
m.Value.Substring(
previousCaptureEnd, currentCaptureLength));
sb.Append(replacement);
previousCaptureEnd = currentCaptureEnd;
}
sb.Append(m.Value.Substring(previousCaptureEnd));
return sb.ToString();
});
}
}
Usage:
var input = @"[assembly: AssemblyFileVersion(""2.0.3.0"")][assembly: AssemblyFileVersion(""2.0.3.0"")]";
var regex = new Regex(@"AssemblyFileVersion\(""(?<version>(\d+\.?){4})""\)");
var result = regex.ReplaceGroup(input , "version", "1.2.3");
Result:
[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 https://stackoverflow.com/questions/6005609/replace-only-some-groups-with-regex